diff --git a/src/DSC/schema_v2_utils.py b/src/DSC/schema_v2_utils.py new file mode 100644 index 000000000..4388bb4ee --- /dev/null +++ b/src/DSC/schema_v2_utils.py @@ -0,0 +1,362 @@ +from typing import Dict, List, Literal + +from forestadmin.agent_toolkit.utils.forest_schema.filterable import FrontendFilterableUtils +from forestadmin.agent_toolkit.utils.forest_schema.type import ( + ForestServerAction, + ForestServerCollection, + ForestServerField, + ForestServerSegment, + ServerValidationType, +) +from forestadmin.datasource_toolkit.interfaces.fields import ColumnAlias, Operator, PrimitiveType +from typing_extensions import NotRequired, TypedDict + + +# TYPING +class SchemaV2Relation(TypedDict): + name: str + type: Literal["ManyToMany", "ManyToOne", "OneToOne", "OneToMany"] + foreignCollection: str + throughCollection: NotRequired[str] + foreignKey: NotRequired[str] + foreignKeyTarget: NotRequired[str] + originKey: NotRequired[str] + originKeyTarget: NotRequired[str] + + +class SchemaV2Field(TypedDict): + name: str + type: ColumnAlias + filterOperators: List[str] + # defaultValue: NotRequired[Any] # TODO + # isRequired: NotRequired[Any] # TODO + enumerations: NotRequired[List[str]] + isPrimaryKey: NotRequired[bool] + isWritable: NotRequired[bool] + isSortable: NotRequired[bool] + validations: NotRequired[List[ServerValidationType]] + + +class SchemaV2Collection(TypedDict): + name: str + fields: List[SchemaV2Field] # to define + relations: List # to define + segments: NotRequired[List[ForestServerSegment]] + actions: NotRequired[List[ForestServerAction]] + isSearchable: NotRequired[bool] + canList: NotRequired[bool] + canCreate: NotRequired[bool] + canUpdate: NotRequired[bool] + canDelete: NotRequired[bool] + canCount: NotRequired[bool] + canChart: NotRequired[bool] + + +# MASKS +SCHEMA_V2_FIELDS_MASK = { + "enumerations": None, + "isPrimaryKey": False, + "isWritable": True, + "isSortable": True, + "validations": [], +} + + +SCHEMA_V2_COLLECTION_MASK = { + "segments": [], + "actions": [], + "isSearchable": True, + "canList": True, + "canCreate": True, + "canUpdate": True, + "canDelete": True, + "canCount": True, + "canChart": True, +} + + +class SchemaV1toV2: + def __init__(self, schema_collections: List[ForestServerCollection]) -> None: + self.initial_schema: List[ForestServerCollection] = schema_collections + + def translate(self) -> List[SchemaV2Collection]: + return self._convert_collection_schema_v1_to_v2(self.initial_schema) + + def _convert_collection_schema_v1_to_v2( + self, schema_collections: List[ForestServerCollection] + ) -> List[SchemaV2Collection]: + schema_collections_v2: List[SchemaV2Collection] = [] + for collection_v1 in schema_collections: + collection_v2: SchemaV2Collection = { + "name": collection_v1["name"], + "fields": self._convert_fields_v1_to_v2(collection_v1["fields"]), + "relations": self._convert_fields_to_relation(collection_v1["fields"]), + "actions": collection_v1["actions"], # type:ignore + "isSearchable": collection_v1["isSearchable"], + "canList": True, + "canCreate": not collection_v1["isReadOnly"], + "canUpdate": not collection_v1["isReadOnly"], + "canDelete": not collection_v1["isReadOnly"], + "canCount": True, + "canChart": True, + } + schema_collections_v2.append(self._template_reduce_collection(collection_v2)) + + return schema_collections_v2 + + def _convert_fields_v1_to_v2(self, fields: List[ForestServerField]) -> List[SchemaV2Field]: + fields_v2: List[SchemaV2Field] = [] + for field_v1 in fields: + if field_v1["relationship"] is not None: # type:ignore + continue + + fields_v2.append( + self._template_reduce_field( + { + "name": field_v1["field"], # type:ignore + "type": field_v1["type"], # type:ignore + "filterOperators": [ + op.value + for op in FrontendFilterableUtils.OPERATOR_BY_TYPES[ + PrimitiveType(field_v1["field"]) # type:ignore + ] # type:ignore + ], # type:ignore + "enumerations": field_v1["enums"] if field_v1["type"] == "Enum" else None, # type:ignore + "isPrimaryKey": field_v1["isPrimaryKey"], # type:ignore + "isSortable": field_v1["isSortable"], # type:ignore + "isWritable": not field_v1["isReadOnly"], # type:ignore + "validations": field_v1["validations"], # type:ignore + } + ) + ) + + return fields_v2 + + def _convert_fields_to_relation(self, fields: List[ForestServerField]) -> List[SchemaV2Relation]: + relation_v2: List[SchemaV2Relation] = [] + for field_v1 in fields: + if field_v1["relationship"] is None: # type:ignore + continue + + relation: SchemaV2Relation = { + "name": field_v1["field"], # type:ignore + "foreignCollection": field_v1["reference"].split(".")[0], # type:ignore + } # type:ignore + if field_v1["relationship"] == "BelongsTo": # type:ignore + relation = { + **relation, + "type": "ManyToOne", + "foreignKeyTarget": field_v1["reference"].split(".")[1], # type:ignore + # TODO: may be impossible because v1 schema doesn't include foreign_keys + "foreignKey": "TODO: N/A", # type:ignore + # doable in the case where it's the reverse of a 1to1 + } + + elif field_v1["relationship"] == "HasMany": # type:ignore + relation = { + **relation, + "type": "OneToMany", + "originKey": "", + # TODO: may be impossible because v1 schema doesn't include foreign_keys + "originKeyTarget": field_v1["reference"].split(".")[1], # type:ignore # TODO: not sure about this + } + + elif field_v1["relationship"] == "HasOne": # type:ignore + relation = { + **relation, + "type": "OneToOne", + "originKey": "", + "originKeyTarget": field_v1["reference"].split(".")[1], # type:ignore + } + + elif field_v1["relationship"] == "BelongsToMany": # type:ignore + reverse_relation = filter( # type:ignore + lambda x: x["fields"] == field_v1["inverseOf"], # type:ignore + self.initial_schema[relation["foreignCollection"]]["fields"], # type:ignore + )[0] + + relation = { + **relation, + "type": "ManyToMany", + "foreignKeyTarget": field_v1["reference"].split(".")[1], # type:ignore + "originKeyTarget": reverse_relation["reference"].split(".")[1], + # TODO: may be impossible because v1 schema doesn't include foreign_keys + "originKey": "TODO: N/A", + "foreignKey": "TODO: N/A", + "throughCollection": "TODO: N/A", + } + relation_v2.append(relation) + + return relation_v2 + + def _template_reduce_field(self, collection: SchemaV2Field) -> SchemaV2Field: + return self._reduce_from_template(collection, SCHEMA_V2_FIELDS_MASK) # type:ignore + + def _template_reduce_collection(self, collection: SchemaV2Collection) -> SchemaV2Collection: + return self._reduce_from_template(collection, SCHEMA_V2_COLLECTION_MASK) # type:ignore + + def _reduce_from_template(self, input, mask): + reduced = {} + for key, value in input: + if key not in mask or input[key] != mask[key]: + reduced[key] = value + return reduced + + +class SchemaV2toV1: + def __init__(self, schema_collections: List[SchemaV2Collection]) -> None: + self.initial_schema = schema_collections + + def translate(self) -> List[ForestServerCollection]: + return self._convert_collection_schema_v2_to_v1(self.initial_schema) + + def _get_value_or_default(self, instance, key, mask): + return instance.get(key, mask[key]) + + def collection_get_value_or_default(self, instance, key): + return self._get_value_or_default(instance, key, SCHEMA_V2_COLLECTION_MASK) + + def field_get_value_or_default(self, instance, key): + return self._get_value_or_default(instance, key, SCHEMA_V2_FIELDS_MASK) + + def _convert_collection_schema_v2_to_v1( + self, collections_v2: List[SchemaV2Collection] + ) -> List[ForestServerCollection]: + schema_collections_v1: List[ForestServerCollection] = [] + for collection_v2 in collections_v2: + schema_collections_v1.append( + { + "name": collection_v2["name"], + "icon": None, + "integration": None, + "isVirtual": False, + "onlyForRelationships": False, + "paginationType": "page", + "fields": self.convert_fields_and_relation(collection_v2["fields"], collection_v2["relations"]), + "isReadOnly": not collection_v2.get("canCreate", SCHEMA_V2_COLLECTION_MASK["canCreate"]), + "isSearchable": collection_v2.get("isSearchable", SCHEMA_V2_COLLECTION_MASK["isSearchable"]), + "actions": collection_v2.get("actions", SCHEMA_V2_COLLECTION_MASK["actions"]), + "segments": collection_v2.get("segments", SCHEMA_V2_COLLECTION_MASK["segments"]), + } + ) + + return schema_collections_v1 + + def convert_fields_and_relation( + self, fields: List[SchemaV2Field], relations: List[SchemaV2Relation] + ) -> List[ForestServerField]: + fields_v1: Dict[str, ForestServerField] = {} + + for field_v2 in fields: + fields_v1[field_v2["name"]] = { + "field": field_v2["name"], + "type": field_v2["type"], + "isPrimaryKey": field_v2.get("isPrimaryKey", SCHEMA_V2_FIELDS_MASK["isPrimaryKey"]), + "isReadOnly": not field_v2.get("isWritable", SCHEMA_V2_FIELDS_MASK["isWritable"]), + "isSortable": field_v2.get("isSortable", SCHEMA_V2_FIELDS_MASK["isSortable"]), + # "defaultValue": None # TODO: need to handle this + "isRequired": len( + [ + *filter( + lambda x: x["type"] == "is present", + field_v2.get("validations", SCHEMA_V2_FIELDS_MASK["validations"]), + ) + ] + ) + > 0, # type:ignore + "enums": ( + field_v2.get("enumerations", SCHEMA_V2_FIELDS_MASK["enumerations"]) + if field_v2["type"] == "Enum" + else None + ), + "isFilterable": FrontendFilterableUtils.is_filterable( + field_v2["type"], + set([Operator(op) for op in field_v2["filterOperators"]]), + ), + "validations": field_v2.get("validations", SCHEMA_V2_FIELDS_MASK["validations"]), + "integration": None, + "isVirtual": False, + "inverseOf": None, + # "relationship": None, not set when it's a field + } + + for rel_v2 in relations: + name = rel_v2["name"] + + if rel_v2["type"] == "OneToMany": + related_field_v2: SchemaV2Field = [ + *filter(lambda x: x["name"] == rel_v2["originKey"], fields) # type:ignore + ][0] + fields_v1[name] = { + **fields_v1[name], + "relationship": "HasMany", + } + + elif rel_v2["type"] == "ManyToOne": + foreign_collection_fields = [ + *filter(lambda x: x["name"] == rel_v2["foreignCollection"], self.initial_schema) # type:ignore + ][0]["fields"] + related_field_v2: SchemaV2Field = [ + *filter(lambda x: x["name"] == rel_v2["foreignKey"], foreign_collection_fields) # type:ignore + ][0] + + fields_v1[name] = { + **fields_v1[name], + "relationship": "BelongsTo", + } + + elif rel_v2["type"] == "OneToOne": + related_field_v2: SchemaV2Field = [ + *filter(lambda x: x["name"] == rel_v2["originKey"], fields) # type:ignore + ][0] + fields_v1[name] = { + **fields_v1[name], + "relationship": "HasOne", + } + + elif rel_v2["type"] == "ManyToMany": + foreign_collection_fields = [ + *filter(lambda x: x["name"] == rel_v2["foreignCollection"], self.initial_schema) # type:ignore + ][0]["fields"] + related_field_v2: SchemaV2Field = [ + *filter(lambda x: x["name"] == rel_v2["foreignKey"], foreign_collection_fields) # type:ignore + ][0] + + fields_v1[name] = { + **fields_v1[name], + "relationship": "BelongsToMany", + } + + # fields_v1[rel_v2["name"]] = { + # "field": rel_v2["name"], + # "type": rel_v2["type"], + # "isPrimaryKey": rel_v2.get("isPrimaryKey", SCHEMA_V2_FIELDS_MASK["isPrimaryKey"]), + # "isReadOnly": not rel_v2.get("isWritable", SCHEMA_V2_FIELDS_MASK["isWritable"]), + # "isSortable": rel_v2.get("isSortable", SCHEMA_V2_FIELDS_MASK["isSortable"]), + # # "defaultValue": None # TODO: need to handle this + # "isRequired": len( + # [ + # *filter( + # lambda x: x["type"] == "is present", + # rel_v2.get("validations", SCHEMA_V2_FIELDS_MASK["validations"]), + # ) + # ] + # ) + # > 0, # type:ignore + # "enums": ( + # rel_v2.get("enumerations", SCHEMA_V2_FIELDS_MASK["enumerations"]) + # if rel_v2["type"] == "Enum" + # else None + # ), + # "isFilterable": FrontendFilterableUtils.is_filterable( + # rel_v2["type"], + # set([Operator(op) for op in rel_v2["filterOperators"]]), + # ), + # "validations": rel_v2.get("validations", SCHEMA_V2_FIELDS_MASK["validations"]), + # "integration": None, + # "isVirtual": False, + # "inverseOf": None, + # # "relationship": None, not set when it's a field + # } + + return [*fields_v1.values()] diff --git a/src/_example/django/django_demo/.forestadmin-schema.json b/src/_example/django/django_demo/.forestadmin-schema.json index 483a9a409..5122a1818 100644 --- a/src/_example/django/django_demo/.forestadmin-schema.json +++ b/src/_example/django/django_demo/.forestadmin-schema.json @@ -2,21 +2,21 @@ "collections": [ { "name": "address", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "city", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -26,7 +26,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -41,9 +40,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "country", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -53,7 +53,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -68,9 +67,12 @@ ] }, { + "field": "customers", + "type": [ + "Uuid" + ], "defaultValue": null, "enums": null, - "field": "customers", "inverseOf": "addresses", "isFilterable": false, "isPrimaryKey": false, @@ -80,15 +82,15 @@ "isVirtual": false, "reference": "customer.id", "relationship": "BelongsToMany", - "type": [ - "String" - ], "validations": [] }, { + "field": "flaskcustomersaddresses_address", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "flaskcustomersaddresses_address", "inverseOf": "address", "isFilterable": false, "isPrimaryKey": false, @@ -98,15 +100,15 @@ "isVirtual": false, "reference": "customers_addresses.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "flaskorder_billing_address", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "flaskorder_billing_address", "inverseOf": "billing_address", "isFilterable": false, "isPrimaryKey": false, @@ -116,15 +118,13 @@ "isVirtual": false, "reference": "order.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -134,13 +134,15 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "order_delivering_address_set_delivering_address", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "order_delivering_address_set_delivering_address", "inverseOf": "delivering_address", "isFilterable": false, "isPrimaryKey": false, @@ -150,15 +152,13 @@ "isVirtual": false, "reference": "order.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "street", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -168,7 +168,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -183,9 +182,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "street_number", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -195,7 +195,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is shorter than", @@ -205,9 +204,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "zip_code", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -217,7 +217,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -235,14 +234,13 @@ }, { "name": "app_address", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [ { @@ -252,9 +250,12 @@ ], "fields": [ { + "field": "billing_orders_billing_address", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "billing_orders_billing_address", "inverseOf": "billing_address", "isFilterable": false, "isPrimaryKey": false, @@ -264,15 +265,13 @@ "isVirtual": false, "reference": "app_order.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "city", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -282,7 +281,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -297,9 +295,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "complete_address", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": false, @@ -309,13 +308,15 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { + "field": "customeraddress_address", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "customeraddress_address", "inverseOf": "address", "isFilterable": false, "isPrimaryKey": false, @@ -325,15 +326,15 @@ "isVirtual": false, "reference": "app_customeraddress.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "customers", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "customers", "inverseOf": "addresses", "isFilterable": false, "isPrimaryKey": false, @@ -343,15 +344,15 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "delivering_orders_delivering_address", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "delivering_orders_delivering_address", "inverseOf": "delivering_address", "isFilterable": false, "isPrimaryKey": false, @@ -361,15 +362,13 @@ "isVirtual": false, "reference": "app_order.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -379,13 +378,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": "France", - "enums": null, "field": "pays", + "type": "String", + "enums": null, + "defaultValue": "France", "integration": null, "inverseOf": null, "isFilterable": true, @@ -395,7 +394,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is shorter than", @@ -405,18 +403,7 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "postal_code", - "integration": null, - "inverseOf": null, - "isFilterable": false, - "isPrimaryKey": false, - "isReadOnly": true, - "isRequired": false, - "isSortable": false, - "isVirtual": false, - "reference": null, "type": [ { "fields": [ @@ -439,12 +426,24 @@ ] } ], + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "street", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -454,7 +453,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -469,9 +467,10 @@ ] }, { - "defaultValue": "75009", - "enums": null, "field": "zip_code", + "type": "String", + "enums": null, + "defaultValue": "75009", "integration": null, "inverseOf": null, "isFilterable": true, @@ -481,7 +480,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is shorter than", @@ -494,14 +492,13 @@ }, { "name": "app_cart", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [ { @@ -511,9 +508,10 @@ ], "fields": [ { - "defaultValue": null, - "enums": null, "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -523,29 +521,29 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "customer_id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, - "isFilterable": false, + "isFilterable": true, "isPrimaryKey": false, "isReadOnly": true, "isRequired": false, "isSortable": false, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "extendedcart", + "type": "Number", "defaultValue": null, "enums": null, - "field": "extendedcart", "inverseOf": "cart", "isFilterable": true, "isPrimaryKey": false, @@ -555,13 +553,13 @@ "isVirtual": false, "reference": "app_extendedcart.cart_id", "relationship": "HasOne", - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -571,13 +569,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -587,7 +585,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -602,9 +599,10 @@ ] }, { + "field": "order", + "type": "Number", "defaultValue": null, "enums": null, - "field": "order", "inverseOf": "cart", "isFilterable": true, "isPrimaryKey": false, @@ -614,21 +612,19 @@ "isVirtual": false, "reference": "app_order.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] } ] }, { "name": "app_customer", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [ { "id": "app_customer-0-export json", @@ -691,9 +687,12 @@ ], "fields": [ { + "field": "Customer_blocked_customer+_from_customer", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "Customer_blocked_customer+_from_customer", "inverseOf": "from_customer", "isFilterable": false, "isPrimaryKey": false, @@ -703,15 +702,15 @@ "isVirtual": false, "reference": "app_customer_blocked_customer.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "Customer_blocked_customer+_to_customer", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "Customer_blocked_customer+_to_customer", "inverseOf": "to_customer", "isFilterable": false, "isPrimaryKey": false, @@ -721,15 +720,13 @@ "isVirtual": false, "reference": "app_customer_blocked_customer.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "TotalSpending", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": false, @@ -739,13 +736,15 @@ "isSortable": false, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "addresses", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "addresses", "inverseOf": "customers", "isFilterable": false, "isPrimaryKey": false, @@ -755,15 +754,13 @@ "isVirtual": false, "reference": "app_address.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "age", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": false, @@ -773,13 +770,13 @@ "isSortable": false, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "avatar", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": false, @@ -789,13 +786,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "birthday_date", + "type": "Dateonly", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -805,13 +802,15 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Dateonly", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "block_by_users", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, "inverseOf": "blocked_customer", "isFilterable": false, "isPrimaryKey": false, @@ -821,15 +820,15 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "blocked_customer", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "blocked_customer", "inverseOf": "block_by_users", "isFilterable": false, "isPrimaryKey": false, @@ -839,15 +838,13 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -857,13 +854,15 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { + "field": "customeraddress_customer", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "customeraddress_customer", "inverseOf": "customer", "isFilterable": false, "isPrimaryKey": false, @@ -873,15 +872,13 @@ "isVirtual": false, "reference": "app_customeraddress.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "first_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -891,7 +888,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -906,9 +902,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "full_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -918,13 +915,13 @@ "isSortable": false, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -934,13 +931,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": false, - "enums": null, "field": "is_vip", + "type": "Boolean", + "enums": null, + "defaultValue": false, "integration": null, "inverseOf": null, "isFilterable": true, @@ -950,13 +947,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Boolean", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "last_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -966,7 +963,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -981,9 +977,12 @@ ] }, { + "field": "orders_customer", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "orders_customer", "inverseOf": "customer", "isFilterable": false, "isPrimaryKey": false, @@ -993,15 +992,15 @@ "isVirtual": false, "reference": "app_order.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "smart_billing_addresses", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "smart_billing_addresses", "inverseOf": null, "isFilterable": false, "isPrimaryKey": false, @@ -1011,15 +1010,15 @@ "isVirtual": false, "reference": "app_address.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "smart_carts", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "smart_carts", "inverseOf": null, "isFilterable": false, "isPrimaryKey": false, @@ -1029,15 +1028,15 @@ "isVirtual": false, "reference": "app_cart.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "smart_delivering_addresses", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "smart_delivering_addresses", "inverseOf": null, "isFilterable": false, "isPrimaryKey": false, @@ -1047,15 +1046,13 @@ "isVirtual": false, "reference": "app_address.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "updated_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1065,28 +1062,27 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] } ] }, { "name": "app_customer_blocked_customer", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "from_customer", + "type": "Number", "defaultValue": null, "enums": null, - "field": "from_customer", "inverseOf": "Customer_blocked_customer+_from_customer", "isFilterable": true, "isPrimaryKey": false, @@ -1096,7 +1092,6 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1106,9 +1101,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1118,13 +1114,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "to_customer", + "type": "Number", "defaultValue": null, "enums": null, - "field": "to_customer", "inverseOf": "Customer_blocked_customer+_to_customer", "isFilterable": true, "isPrimaryKey": false, @@ -1134,7 +1130,6 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1147,21 +1142,21 @@ }, { "name": "app_customeraddress", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "address", + "type": "Number", "defaultValue": null, "enums": null, - "field": "address", "inverseOf": "customeraddress_address", "isFilterable": true, "isPrimaryKey": false, @@ -1171,7 +1166,6 @@ "isVirtual": false, "reference": "app_address.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1181,9 +1175,10 @@ ] }, { + "field": "customer", + "type": "Number", "defaultValue": null, "enums": null, - "field": "customer", "inverseOf": "customeraddress_customer", "isFilterable": true, "isPrimaryKey": false, @@ -1193,7 +1188,6 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1203,9 +1197,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1215,28 +1210,27 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] } ] }, { "name": "app_discountcart", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "discount", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1246,7 +1240,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [ { "type": "is present", @@ -1256,9 +1249,10 @@ ] }, { + "field": "extendedcart", + "type": "Number", "defaultValue": null, "enums": null, - "field": "extendedcart", "inverseOf": "discount", "isFilterable": true, "isPrimaryKey": false, @@ -1268,13 +1262,13 @@ "isVirtual": false, "reference": "app_extendedcart.discount_id", "relationship": "HasOne", - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1284,28 +1278,27 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] } ] }, { "name": "app_extendedcart", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "cart", + "type": "Number", "defaultValue": null, "enums": null, - "field": "cart", "inverseOf": "extendedcart", "isFilterable": true, "isPrimaryKey": false, @@ -1315,7 +1308,6 @@ "isVirtual": false, "reference": "app_cart.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1325,9 +1317,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "cart_id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1337,7 +1330,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [ { "type": "is present", @@ -1347,9 +1339,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "color", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1359,7 +1352,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -1374,9 +1366,10 @@ ] }, { + "field": "discount", + "type": "Number", "defaultValue": null, "enums": null, - "field": "discount", "inverseOf": "extendedcart", "isFilterable": true, "isPrimaryKey": false, @@ -1386,21 +1379,19 @@ "isVirtual": false, "reference": "app_discountcart.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] } ] }, { "name": "app_order", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [ { "id": "app_order-0-export json", @@ -1428,8 +1419,8 @@ }, { "field": "customer", - "value": "", - "defaultValue": "", + "value": null, + "defaultValue": null, "description": "", "enums": null, "hook": null, @@ -1451,7 +1442,7 @@ { "id": "app_order-1-refund order(s)", "name": "Refund order(s)", - "type": "bulk", + "type": "single", "baseUrl": null, "endpoint": "/forest/_actions/app_order/1/refund order(s)", "httpMethod": "POST", @@ -1509,9 +1500,10 @@ ], "fields": [ { + "field": "billing_address", + "type": "Number", "defaultValue": null, "enums": null, - "field": "billing_address", "inverseOf": "billing_orders_billing_address", "isFilterable": true, "isPrimaryKey": false, @@ -1521,7 +1513,6 @@ "isVirtual": false, "reference": "app_address.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1531,9 +1522,10 @@ ] }, { + "field": "cart", + "type": "Number", "defaultValue": null, "enums": null, - "field": "cart", "inverseOf": "order", "isFilterable": true, "isPrimaryKey": false, @@ -1543,13 +1535,13 @@ "isVirtual": false, "reference": "app_cart.order_id", "relationship": "HasOne", - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "cost", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1559,7 +1551,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [ { "type": "is present", @@ -1579,9 +1570,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1591,13 +1583,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { + "field": "customer", + "type": "Number", "defaultValue": null, "enums": null, - "field": "customer", "inverseOf": "orders_customer", "isFilterable": true, "isPrimaryKey": false, @@ -1607,13 +1599,13 @@ "isVirtual": false, "reference": "app_customer.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "customer_first_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1623,13 +1615,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "customer_full_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": false, @@ -1639,13 +1631,13 @@ "isSortable": false, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { + "field": "delivering_address", + "type": "Number", "defaultValue": null, "enums": null, - "field": "delivering_address", "inverseOf": "delivering_orders_delivering_address", "isFilterable": true, "isPrimaryKey": false, @@ -1655,7 +1647,6 @@ "isVirtual": false, "reference": "app_address.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1665,9 +1656,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1677,13 +1669,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "ordered_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1693,18 +1685,34 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { + "field": "ordered_date", + "type": "Date", + "enums": null, "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "status", + "type": "Enum", "enums": [ "PENDING", "DISPATCHED", "DELIVERED", "REJECTED" ], - "field": "status", + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1714,7 +1722,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Enum", "validations": [ { "type": "is present", @@ -1729,9 +1736,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "updated_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1741,28 +1749,29 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] } ] }, { "name": "auth_group", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "Group_permissions+_group", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "Group_permissions+_group", "inverseOf": "group", "isFilterable": false, "isPrimaryKey": false, @@ -1772,15 +1781,15 @@ "isVirtual": false, "reference": "auth_group_permissions.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "User_groups+_group", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "User_groups+_group", "inverseOf": "group", "isFilterable": false, "isPrimaryKey": false, @@ -1790,15 +1799,13 @@ "isVirtual": false, "reference": "auth_user_groups.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1808,13 +1815,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1824,7 +1831,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -1839,9 +1845,12 @@ ] }, { + "field": "permissions", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "permissions", "inverseOf": "group", "isFilterable": false, "isPrimaryKey": false, @@ -1851,15 +1860,15 @@ "isVirtual": false, "reference": "auth_permission.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "user", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "user", "inverseOf": "groups", "isFilterable": false, "isPrimaryKey": false, @@ -1869,30 +1878,27 @@ "isVirtual": false, "reference": "auth_user.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] } ] }, { "name": "auth_group_permissions", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "group", + "type": "Number", "defaultValue": null, "enums": null, - "field": "group", "inverseOf": "Group_permissions+_group", "isFilterable": true, "isPrimaryKey": false, @@ -1902,7 +1908,6 @@ "isVirtual": false, "reference": "auth_group.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1912,9 +1917,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -1924,13 +1930,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "permission", + "type": "Number", "defaultValue": null, "enums": null, - "field": "permission", "inverseOf": "Group_permissions+_permission", "isFilterable": true, "isPrimaryKey": false, @@ -1940,7 +1946,6 @@ "isVirtual": false, "reference": "auth_permission.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -1953,21 +1958,23 @@ }, { "name": "auth_permission", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "Group_permissions+_permission", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "Group_permissions+_permission", "inverseOf": "permission", "isFilterable": false, "isPrimaryKey": false, @@ -1977,15 +1984,15 @@ "isVirtual": false, "reference": "auth_group_permissions.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "User_user_permissions+_permission", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "User_user_permissions+_permission", "inverseOf": "permission", "isFilterable": false, "isPrimaryKey": false, @@ -1995,15 +2002,13 @@ "isVirtual": false, "reference": "auth_user_user_permissions.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "codename", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2013,7 +2018,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2028,9 +2032,10 @@ ] }, { + "field": "content_type", + "type": "Number", "defaultValue": null, "enums": null, - "field": "content_type", "inverseOf": "permission_content_type", "isFilterable": true, "isPrimaryKey": false, @@ -2040,7 +2045,6 @@ "isVirtual": false, "reference": "django_content_type.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -2050,9 +2054,12 @@ ] }, { + "field": "group", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "group", "inverseOf": "permissions", "isFilterable": false, "isPrimaryKey": false, @@ -2062,15 +2069,13 @@ "isVirtual": false, "reference": "auth_group.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2080,13 +2085,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2096,7 +2101,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2111,9 +2115,12 @@ ] }, { + "field": "user", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "user", "inverseOf": "user_permissions", "isFilterable": false, "isPrimaryKey": false, @@ -2123,30 +2130,29 @@ "isVirtual": false, "reference": "auth_user.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] } ] }, { "name": "auth_user", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "User_groups+_user", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "User_groups+_user", "inverseOf": "user", "isFilterable": false, "isPrimaryKey": false, @@ -2156,15 +2162,15 @@ "isVirtual": false, "reference": "auth_user_groups.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { + "field": "User_user_permissions+_user", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "User_user_permissions+_user", "inverseOf": "user", "isFilterable": false, "isPrimaryKey": false, @@ -2174,15 +2180,13 @@ "isVirtual": false, "reference": "auth_user_user_permissions.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "date_joined", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2192,13 +2196,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "email", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2208,7 +2212,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is shorter than", @@ -2218,9 +2221,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "first_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2230,7 +2234,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is shorter than", @@ -2240,9 +2243,12 @@ ] }, { + "field": "groups", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "groups", "inverseOf": "user", "isFilterable": false, "isPrimaryKey": false, @@ -2252,15 +2258,13 @@ "isVirtual": false, "reference": "auth_group.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2270,13 +2274,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": true, - "enums": null, "field": "is_active", + "type": "Boolean", + "enums": null, + "defaultValue": true, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2286,13 +2290,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Boolean", "validations": [] }, { - "defaultValue": false, - "enums": null, "field": "is_staff", + "type": "Boolean", + "enums": null, + "defaultValue": false, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2302,13 +2306,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Boolean", "validations": [] }, { - "defaultValue": false, - "enums": null, "field": "is_superuser", + "type": "Boolean", + "enums": null, + "defaultValue": false, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2318,13 +2322,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Boolean", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "last_login", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2334,13 +2338,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "last_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2350,7 +2354,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is shorter than", @@ -2360,9 +2363,12 @@ ] }, { + "field": "logentry_user", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "logentry_user", "inverseOf": "user", "isFilterable": false, "isPrimaryKey": false, @@ -2372,15 +2378,13 @@ "isVirtual": false, "reference": "django_admin_log.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "password", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2390,7 +2394,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2405,9 +2408,12 @@ ] }, { + "field": "user_permissions", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "user_permissions", "inverseOf": "user", "isFilterable": false, "isPrimaryKey": false, @@ -2417,15 +2423,13 @@ "isVirtual": false, "reference": "auth_permission.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "username", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2435,7 +2439,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2453,21 +2456,21 @@ }, { "name": "auth_user_groups", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "group", + "type": "Number", "defaultValue": null, "enums": null, - "field": "group", "inverseOf": "User_groups+_group", "isFilterable": true, "isPrimaryKey": false, @@ -2477,7 +2480,6 @@ "isVirtual": false, "reference": "auth_group.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -2487,9 +2489,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2499,13 +2502,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "user", + "type": "Number", "defaultValue": null, "enums": null, - "field": "user", "inverseOf": "User_groups+_user", "isFilterable": true, "isPrimaryKey": false, @@ -2515,7 +2518,6 @@ "isVirtual": false, "reference": "auth_user.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -2528,21 +2530,21 @@ }, { "name": "auth_user_user_permissions", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2552,13 +2554,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "permission", + "type": "Number", "defaultValue": null, "enums": null, - "field": "permission", "inverseOf": "User_user_permissions+_permission", "isFilterable": true, "isPrimaryKey": false, @@ -2568,7 +2570,6 @@ "isVirtual": false, "reference": "auth_permission.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -2578,9 +2579,10 @@ ] }, { + "field": "user", + "type": "Number", "defaultValue": null, "enums": null, - "field": "user", "inverseOf": "User_user_permissions+_user", "isFilterable": true, "isPrimaryKey": false, @@ -2590,7 +2592,6 @@ "isVirtual": false, "reference": "auth_user.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -2603,21 +2604,21 @@ }, { "name": "cart", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2627,13 +2628,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2643,13 +2644,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2659,7 +2660,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2674,9 +2674,10 @@ ] }, { + "field": "order", + "type": "Number", "defaultValue": null, "enums": null, - "field": "order", "inverseOf": "flaskcart_order", "isFilterable": true, "isPrimaryKey": false, @@ -2686,28 +2687,29 @@ "isVirtual": false, "reference": "order.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] } ] }, { "name": "customer", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "addresses", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "addresses", "inverseOf": "customers", "isFilterable": false, "isPrimaryKey": false, @@ -2717,15 +2719,13 @@ "isVirtual": false, "reference": "address.id", "relationship": "BelongsToMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "age", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2735,13 +2735,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "avatar", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": false, @@ -2751,13 +2751,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "birthday_date", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2767,13 +2767,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "first_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2783,7 +2783,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2798,9 +2797,12 @@ ] }, { + "field": "flaskcustomersaddresses_customer", + "type": [ + "Uuid" + ], "defaultValue": null, "enums": null, - "field": "flaskcustomersaddresses_customer", "inverseOf": "customer", "isFilterable": false, "isPrimaryKey": false, @@ -2810,15 +2812,15 @@ "isVirtual": false, "reference": "customers_addresses.id", "relationship": "HasMany", - "type": [ - "String" - ], "validations": [] }, { + "field": "flaskorder_customer", + "type": [ + "Uuid" + ], "defaultValue": null, "enums": null, - "field": "flaskorder_customer", "inverseOf": "customer", "isFilterable": false, "isPrimaryKey": false, @@ -2828,31 +2830,40 @@ "isVirtual": false, "reference": "order.id", "relationship": "HasMany", - "type": [ - "String" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Uuid", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, - "isFilterable": false, + "isFilterable": true, "isPrimaryKey": true, "isReadOnly": false, - "isRequired": false, + "isRequired": true, "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", - "validations": [] + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 32, + "message": null + } + ] }, { - "defaultValue": null, - "enums": null, "field": "is_vip", + "type": "Boolean", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2862,13 +2873,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Boolean", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "last_name", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2878,7 +2889,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -2896,21 +2906,21 @@ }, { "name": "customers_addresses", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { + "field": "address", + "type": "Number", "defaultValue": null, "enums": null, - "field": "address", "inverseOf": "flaskcustomersaddresses_address", "isFilterable": true, "isPrimaryKey": false, @@ -2920,7 +2930,6 @@ "isVirtual": false, "reference": "address.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -2930,25 +2939,32 @@ ] }, { + "field": "customer", + "type": "Uuid", "defaultValue": null, "enums": null, - "field": "customer", "inverseOf": "flaskcustomersaddresses_customer", "isFilterable": true, "isPrimaryKey": false, "isReadOnly": false, - "isRequired": false, + "isRequired": true, "isSortable": true, "isVirtual": false, "reference": "customer.id", "relationship": "BelongsTo", - "type": "String", - "validations": [] + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2958,32 +2974,31 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] } ] }, { "name": "django_admin_log", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, + "field": "action_flag", + "type": "Enum", "enums": [ "1", "2", "3" ], - "field": "action_flag", + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -2993,7 +3008,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Enum", "validations": [ { "type": "is present", @@ -3003,9 +3017,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "action_time", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3015,13 +3030,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "change_message", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3031,13 +3046,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { + "field": "content_type", + "type": "Number", "defaultValue": null, "enums": null, - "field": "content_type", "inverseOf": "logentry_content_type", "isFilterable": true, "isPrimaryKey": false, @@ -3047,13 +3062,13 @@ "isVirtual": false, "reference": "django_content_type.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3063,13 +3078,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "object_id", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3079,13 +3094,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "object_repr", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3095,7 +3110,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -3110,9 +3124,10 @@ ] }, { + "field": "user", + "type": "Number", "defaultValue": null, "enums": null, - "field": "user", "inverseOf": "logentry_user", "isFilterable": true, "isPrimaryKey": false, @@ -3122,7 +3137,6 @@ "isVirtual": false, "reference": "auth_user.id", "relationship": "BelongsTo", - "type": "Number", "validations": [ { "type": "is present", @@ -3135,21 +3149,21 @@ }, { "name": "django_content_type", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "app_label", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3159,7 +3173,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -3174,9 +3187,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3186,13 +3200,15 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { + "field": "logentry_content_type", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "logentry_content_type", "inverseOf": "content_type", "isFilterable": false, "isPrimaryKey": false, @@ -3202,15 +3218,13 @@ "isVirtual": false, "reference": "django_admin_log.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "model", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3220,7 +3234,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -3235,9 +3248,12 @@ ] }, { + "field": "permission_content_type", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "permission_content_type", "inverseOf": "content_type", "isFilterable": false, "isPrimaryKey": false, @@ -3247,30 +3263,27 @@ "isVirtual": false, "reference": "auth_permission.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] } ] }, { "name": "django_session", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "expire_date", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3280,7 +3293,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [ { "type": "is present", @@ -3290,9 +3302,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "session_data", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3302,7 +3315,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -3312,9 +3324,10 @@ ] }, { - "defaultValue": null, - "enums": null, "field": "session_key", + "type": "String", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3324,7 +3337,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "String", "validations": [ { "type": "is present", @@ -3342,21 +3354,21 @@ }, { "name": "order", - "isVirtual": false, "icon": null, - "isReadOnly": false, "integration": null, + "isReadOnly": false, "isSearchable": true, + "isVirtual": false, "onlyForRelationships": false, "paginationType": "page", - "searchField": null, "actions": [], "segments": [], "fields": [ { - "defaultValue": null, - "enums": null, "field": "amount", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3366,7 +3378,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [ { "type": "is present", @@ -3376,9 +3387,10 @@ ] }, { + "field": "billing_address", + "type": "Number", "defaultValue": null, "enums": null, - "field": "billing_address", "inverseOf": "flaskorder_billing_address", "isFilterable": true, "isPrimaryKey": false, @@ -3388,13 +3400,13 @@ "isVirtual": false, "reference": "address.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3404,13 +3416,13 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Date", "validations": [] }, { + "field": "customer", + "type": "Uuid", "defaultValue": null, "enums": null, - "field": "customer", "inverseOf": "flaskorder_customer", "isFilterable": true, "isPrimaryKey": false, @@ -3420,13 +3432,13 @@ "isVirtual": false, "reference": "customer.id", "relationship": "BelongsTo", - "type": "String", "validations": [] }, { + "field": "delivering_address", + "type": "Number", "defaultValue": null, "enums": null, - "field": "delivering_address", "inverseOf": "order_delivering_address_set_delivering_address", "isFilterable": true, "isPrimaryKey": false, @@ -3436,13 +3448,15 @@ "isVirtual": false, "reference": "address.id", "relationship": "BelongsTo", - "type": "Number", "validations": [] }, { + "field": "flaskcart_order", + "type": [ + "Number" + ], "defaultValue": null, "enums": null, - "field": "flaskcart_order", "inverseOf": "order", "isFilterable": false, "isPrimaryKey": false, @@ -3452,15 +3466,13 @@ "isVirtual": false, "reference": "cart.id", "relationship": "HasMany", - "type": [ - "Number" - ], "validations": [] }, { - "defaultValue": null, - "enums": null, "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3470,18 +3482,18 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Number", "validations": [] }, { - "defaultValue": null, + "field": "status", + "type": "Enum", "enums": [ "PENDING", "DISPATCHED", "DELIVERED", "REJECTED" ], - "field": "status", + "defaultValue": null, "integration": null, "inverseOf": null, "isFilterable": true, @@ -3491,7 +3503,6 @@ "isSortable": true, "isVirtual": false, "reference": null, - "type": "Enum", "validations": [ { "type": "is present", @@ -3510,10 +3521,11 @@ ], "meta": { "liana": "agent-python", - "liana_version": "1.4.0", + "liana_version": "1.5.6", "stack": { "engine": "python", - "engine_version": "3.10.11" - } + "engine_version": "3.11.3" + }, + "schemaFileHash": "94008f891a07a15668f272455796cec49a8c8526" } } \ No newline at end of file diff --git a/src/_example/django/django_demo/.forestadmin-schema_full_v2.json b/src/_example/django/django_demo/.forestadmin-schema_full_v2.json new file mode 100644 index 000000000..780e2de17 --- /dev/null +++ b/src/_example/django/django_demo/.forestadmin-schema_full_v2.json @@ -0,0 +1,4217 @@ +{ + "collections": [ + { + "name": "address", + "fields": [ + { + "name": "city", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "country", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "street", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "street_number", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is shorter than", + "value": 2, + "message": null + } + ] + }, + { + "name": "zip_code", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 5, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "customers", + "type": "ManyToMany", + "foreignCollection": "customer", + "throughCollection": "customers_addresses", + "originKey": "address_id", + "originKeyTarget": "id", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "flaskcustomersaddresses_address", + "type": "OneToMany", + "foreignCollection": "customers_addresses", + "originKey": "address_id", + "originKeyTarget": "id" + }, + { + "name": "flaskorder_billing_address", + "type": "OneToMany", + "foreignCollection": "order", + "originKey": "billing_address_id", + "originKeyTarget": "id" + }, + { + "name": "order_delivering_address_set_delivering_address", + "type": "OneToMany", + "foreignCollection": "order", + "originKey": "delivering_address_id", + "originKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_address", + "fields": [ + { + "name": "city", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "complete_address", + "type": "String", + "filterOperators": [], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "pays", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": "France", + "validations": [ + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "postal_code", + "type": [ + { + "fields": [ + { + "field": "codePostal", + "type": "String" + }, + { + "field": "codeCommune", + "type": "String" + }, + { + "field": "nomCommune", + "type": "String" + }, + { + "field": "libelleAcheminement", + "type": "String" + } + ] + } + ], + "filterOperators": [], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "street", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "zip_code", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": "75009", + "validations": [ + { + "type": "is shorter than", + "value": 5, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "billing_orders_billing_address", + "type": "OneToMany", + "foreignCollection": "app_order", + "originKey": "billing_address_id", + "originKeyTarget": "id" + }, + { + "name": "customeraddress_address", + "type": "OneToMany", + "foreignCollection": "app_customeraddress", + "originKey": "address_id", + "originKeyTarget": "id" + }, + { + "name": "customers", + "type": "ManyToMany", + "foreignCollection": "app_customer", + "throughCollection": "app_customeraddress", + "originKey": "address_id", + "originKeyTarget": "id", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "delivering_orders_delivering_address", + "type": "OneToMany", + "foreignCollection": "app_order", + "originKey": "delivering_address_id", + "originKeyTarget": "id" + } + ], + "actions": [], + "segments": [ + { + "id": "app_address.highOrderDelivery", + "name": "highOrderDelivery" + } + ], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": false, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_cart", + "fields": [ + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "IncludesAll", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "order_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "extendedcart", + "type": "OneToOne", + "foreignCollection": "app_extendedcart", + "originKey": "cart_id", + "originKeyTarget": "id" + }, + { + "name": "order", + "type": "ManyToOne", + "foreignCollection": "app_order", + "foreignKey": "order_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [ + { + "id": "app_cart.No order", + "name": "No order" + } + ], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_customer", + "fields": [ + { + "name": "TotalSpending", + "type": "Number", + "filterOperators": [], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "age", + "type": "Number", + "filterOperators": [], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "avatar", + "type": "String", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "birthday_date", + "type": "Dateonly", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "full_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "GreaterThan", + "In", + "IncludesAll", + "LessThan", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "is_vip", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": false, + "validations": [] + }, + { + "name": "last_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "updated_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "Customer_blocked_customer+_from_customer", + "type": "OneToMany", + "foreignCollection": "app_customer_blocked_customer", + "originKey": "from_customer_id", + "originKeyTarget": "id" + }, + { + "name": "Customer_blocked_customer+_to_customer", + "type": "OneToMany", + "foreignCollection": "app_customer_blocked_customer", + "originKey": "to_customer_id", + "originKeyTarget": "id" + }, + { + "name": "addresses", + "type": "ManyToMany", + "foreignCollection": "app_address", + "throughCollection": "app_customeraddress", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "block_by_users", + "type": "ManyToMany", + "foreignCollection": "app_customer", + "throughCollection": "app_customer_blocked_customer", + "originKey": "to_customer_id", + "originKeyTarget": "id", + "foreignKey": "from_customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "blocked_customer", + "type": "ManyToMany", + "foreignCollection": "app_customer", + "throughCollection": "app_customer_blocked_customer", + "originKey": "from_customer_id", + "originKeyTarget": "id", + "foreignKey": "to_customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "customeraddress_customer", + "type": "OneToMany", + "foreignCollection": "app_customeraddress", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "orders_customer", + "type": "OneToMany", + "foreignCollection": "app_order", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "smart_billing_addresses", + "type": "ManyToMany", + "foreignCollection": "app_address", + "throughCollection": "app_order", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "billing_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "smart_carts", + "type": "OneToMany", + "foreignCollection": "app_cart", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "smart_delivering_addresses", + "type": "ManyToMany", + "foreignCollection": "app_address", + "throughCollection": "app_order", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "delivering_address_id", + "foreignKeyTarget": "id" + } + ], + "actions": [ + { + "id": "app_customer-0-export json", + "name": "Export json", + "scope": "bulk", + "endpoint": "/forest/_actions/app_customer/0/export json", + "download": true, + "isDynamicForm": false, + "fields": [] + }, + { + "id": "app_customer-1-age operation", + "name": "Age operation", + "scope": "single", + "endpoint": "/forest/_actions/app_customer/1/age operation", + "download": false, + "isDynamicForm": true + } + ], + "segments": [ + { + "id": "app_customer.VIP customers", + "name": "VIP customers" + }, + { + "id": "app_customer.with french address", + "name": "with french address" + } + ], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_customer_blocked_customer", + "fields": [ + { + "name": "from_customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "to_customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "from_customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "from_customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "to_customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "to_customer_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_customeraddress", + "fields": [ + { + "name": "address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "address", + "type": "ManyToOne", + "foreignCollection": "app_address", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_discountcart", + "fields": [ + { + "name": "discount", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "extendedcart", + "type": "OneToOne", + "foreignCollection": "app_extendedcart", + "originKey": "discount_id", + "originKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_extendedcart", + "fields": [ + { + "name": "cart_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "color", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 20, + "message": null + } + ] + }, + { + "name": "discount_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "cart", + "type": "ManyToOne", + "foreignCollection": "app_cart", + "foreignKey": "cart_id", + "foreignKeyTarget": "id" + }, + { + "name": "discount", + "type": "ManyToOne", + "foreignCollection": "app_discountcart", + "foreignKey": "discount_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "app_order", + "fields": [ + { + "name": "billing_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "cost", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is greater than", + "value": 0, + "message": null + }, + { + "type": "is greater than", + "value": 0, + "message": null + } + ] + }, + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "customer_first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "customer_full_name", + "type": "String", + "filterOperators": [], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "delivering_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "ordered_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "ordered_date", + "type": "Date", + "filterOperators": [], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": false, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "status", + "type": "Enum", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": [ + "PENDING", + "DISPATCHED", + "DELIVERED", + "REJECTED" + ], + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 10, + "message": null + } + ] + }, + { + "name": "updated_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "billing_address", + "type": "ManyToOne", + "foreignCollection": "app_address", + "foreignKey": "billing_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "cart", + "type": "OneToOne", + "foreignCollection": "app_cart", + "originKey": "order_id", + "originKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "delivering_address", + "type": "ManyToOne", + "foreignCollection": "app_address", + "foreignKey": "delivering_address_id", + "foreignKeyTarget": "id" + } + ], + "actions": [ + { + "id": "app_order-0-export json", + "name": "Export json", + "scope": "global", + "endpoint": "/forest/_actions/app_order/0/export json", + "download": true, + "isDynamicForm": false, + "fields": [ + { + "name": "dummy field", + "type": "String", + "description": "", + "value": "", + "prefillValue": "", + "isReadOnly": false, + "isRequired": false, + "widget": null + }, + { + "name": "customer", + "type": "Number", + "description": "", + "value": null, + "prefillValue": null, + "isReadOnly": false, + "isRequired": true, + "widget": null, + "reference": "app_customer.id" + } + ] + }, + { + "id": "app_order-1-refund order(s)", + "name": "Refund order(s)", + "scope": "single", + "endpoint": "/forest/_actions/app_order/1/refund order(s)", + "download": false, + "isDynamicForm": false, + "fields": [ + { + "name": "reason", + "type": "String", + "description": "", + "value": "", + "prefillValue": "", + "isReadOnly": false, + "isRequired": false, + "widget": null + } + ] + } + ], + "segments": [ + { + "id": "app_order.Delivered order", + "name": "Delivered order" + }, + { + "id": "app_order.Dispatched order", + "name": "Dispatched order" + }, + { + "id": "app_order.Pending order", + "name": "Pending order" + }, + { + "id": "app_order.Rejected order", + "name": "Rejected order" + }, + { + "id": "app_order.Suspicious order", + "name": "Suspicious order" + }, + { + "id": "app_order.newly_created", + "name": "newly_created" + } + ], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "auth_group", + "fields": [ + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "Group_permissions+_group", + "type": "OneToMany", + "foreignCollection": "auth_group_permissions", + "originKey": "group_id", + "originKeyTarget": "id" + }, + { + "name": "User_groups+_group", + "type": "OneToMany", + "foreignCollection": "auth_user_groups", + "originKey": "group_id", + "originKeyTarget": "id" + }, + { + "name": "permissions", + "type": "ManyToMany", + "foreignCollection": "auth_permission", + "throughCollection": "auth_group_permissions", + "originKey": "group_id", + "originKeyTarget": "id", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToMany", + "foreignCollection": "auth_user", + "throughCollection": "auth_user_groups", + "originKey": "group_id", + "originKeyTarget": "id", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "auth_group_permissions", + "fields": [ + { + "name": "group_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "permission_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "group", + "type": "ManyToOne", + "foreignCollection": "auth_group", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "permission", + "type": "ManyToOne", + "foreignCollection": "auth_permission", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "auth_permission", + "fields": [ + { + "name": "codename", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "name": "content_type_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "Group_permissions+_permission", + "type": "OneToMany", + "foreignCollection": "auth_group_permissions", + "originKey": "permission_id", + "originKeyTarget": "id" + }, + { + "name": "User_user_permissions+_permission", + "type": "OneToMany", + "foreignCollection": "auth_user_user_permissions", + "originKey": "permission_id", + "originKeyTarget": "id" + }, + { + "name": "content_type", + "type": "ManyToOne", + "foreignCollection": "django_content_type", + "foreignKey": "content_type_id", + "foreignKeyTarget": "id" + }, + { + "name": "group", + "type": "ManyToMany", + "foreignCollection": "auth_group", + "throughCollection": "auth_group_permissions", + "originKey": "permission_id", + "originKeyTarget": "id", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToMany", + "foreignCollection": "auth_user", + "throughCollection": "auth_user_user_permissions", + "originKey": "permission_id", + "originKeyTarget": "id", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "auth_user", + "fields": [ + { + "name": "date_joined", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "email", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "is_active", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": true, + "validations": [] + }, + { + "name": "is_staff", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": false, + "validations": [] + }, + { + "name": "is_superuser", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": false, + "validations": [] + }, + { + "name": "last_login", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "last_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "name": "password", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 128, + "message": null + } + ] + }, + { + "name": "username", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "User_groups+_user", + "type": "OneToMany", + "foreignCollection": "auth_user_groups", + "originKey": "user_id", + "originKeyTarget": "id" + }, + { + "name": "User_user_permissions+_user", + "type": "OneToMany", + "foreignCollection": "auth_user_user_permissions", + "originKey": "user_id", + "originKeyTarget": "id" + }, + { + "name": "groups", + "type": "ManyToMany", + "foreignCollection": "auth_group", + "throughCollection": "auth_user_groups", + "originKey": "user_id", + "originKeyTarget": "id", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "logentry_user", + "type": "OneToMany", + "foreignCollection": "django_admin_log", + "originKey": "user_id", + "originKeyTarget": "id" + }, + { + "name": "user_permissions", + "type": "ManyToMany", + "foreignCollection": "auth_permission", + "throughCollection": "auth_user_user_permissions", + "originKey": "user_id", + "originKeyTarget": "id", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "auth_user_groups", + "fields": [ + { + "name": "group_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "user_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "group", + "type": "ManyToOne", + "foreignCollection": "auth_group", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToOne", + "foreignCollection": "auth_user", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "auth_user_user_permissions", + "fields": [ + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "permission_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "user_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "permission", + "type": "ManyToOne", + "foreignCollection": "auth_permission", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToOne", + "foreignCollection": "auth_user", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "cart", + "fields": [ + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "order_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "order", + "type": "ManyToOne", + "foreignCollection": "order", + "foreignKey": "order_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "customer", + "fields": [ + { + "name": "age", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "avatar", + "type": "String", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "birthday_date", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "id", + "type": "Uuid", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "Missing", + "NotEqual", + "NotIn", + "Present", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 32, + "message": null + } + ] + }, + { + "name": "is_vip", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "last_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "addresses", + "type": "ManyToMany", + "foreignCollection": "address", + "throughCollection": "customers_addresses", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "flaskcustomersaddresses_customer", + "type": "OneToMany", + "foreignCollection": "customers_addresses", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "flaskorder_customer", + "type": "OneToMany", + "foreignCollection": "order", + "originKey": "customer_id", + "originKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "customers_addresses", + "fields": [ + { + "name": "address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "customer_id", + "type": "Uuid", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "Missing", + "NotEqual", + "NotIn", + "Present", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + } + ], + "relations": [ + { + "name": "address", + "type": "ManyToOne", + "foreignCollection": "address", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "django_admin_log", + "fields": [ + { + "name": "action_flag", + "type": "Enum", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": [ + "1", + "2", + "3" + ], + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "action_time", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "change_message", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "content_type_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "object_id", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "object_repr", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 200, + "message": null + } + ] + }, + { + "name": "user_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "content_type", + "type": "ManyToOne", + "foreignCollection": "django_content_type", + "foreignKey": "content_type_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToOne", + "foreignCollection": "auth_user", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "django_content_type", + "fields": [ + { + "name": "app_label", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "model", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "logentry_content_type", + "type": "OneToMany", + "foreignCollection": "django_admin_log", + "originKey": "content_type_id", + "originKeyTarget": "id" + }, + { + "name": "permission_content_type", + "type": "OneToMany", + "foreignCollection": "auth_permission", + "originKey": "content_type_id", + "originKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "django_session", + "fields": [ + { + "name": "expire_date", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "session_data", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "session_key", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 40, + "message": null + } + ] + } + ], + "relations": [], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + }, + { + "name": "order", + "fields": [ + { + "name": "amount", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "billing_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "customer_id", + "type": "Uuid", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "Missing", + "NotEqual", + "NotIn", + "Present", + "StartsWith" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "delivering_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": null, + "isPrimaryKey": true, + "isSortable": true, + "isWritable": false, + "prefillFormValue": null, + "validations": [] + }, + { + "name": "status", + "type": "Enum", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": [ + "PENDING", + "DISPATCHED", + "DELIVERED", + "REJECTED" + ], + "isPrimaryKey": false, + "isSortable": true, + "isWritable": true, + "prefillFormValue": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 10, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "billing_address", + "type": "ManyToOne", + "foreignCollection": "address", + "foreignKey": "billing_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "delivering_address", + "type": "ManyToOne", + "foreignCollection": "address", + "foreignKey": "delivering_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "flaskcart_order", + "type": "OneToMany", + "foreignCollection": "cart", + "originKey": "order_id", + "originKeyTarget": "id" + } + ], + "actions": [], + "segments": [], + "canSearch": true, + "canList": true, + "canCreate": true, + "canUpdate": true, + "canDelete": true, + "canCount": true, + "canChart": true, + "canNativeQuery": true + } + ], + "meta": { + "agent": "agent-python", + "agent_version": "1.5.5", + "stack": { + "engine": "python", + "engine_version": "3.10.11" + }, + "datasources": [ + { + "name": "DjangoDatasource", + "version": "1.5.5", + "django_version": "4.2.11" + } + ] + } +} \ No newline at end of file diff --git a/src/_example/django/django_demo/.forestadmin-schema_json_api.json b/src/_example/django/django_demo/.forestadmin-schema_json_api.json new file mode 100644 index 000000000..972ed6b5a --- /dev/null +++ b/src/_example/django/django_demo/.forestadmin-schema_json_api.json @@ -0,0 +1,3865 @@ +{ + "data": [ + { + "id": "address", + "type": "collections", + "attributes": { + "name": "address", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "city", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "field": "country", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "field": "customers", + "type": [ + "Uuid" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "addresses", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "customer.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "flaskcustomersaddresses_address", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "address", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "customers_addresses.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "flaskorder_billing_address", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "billing_address", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "order.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "order_delivering_address_set_delivering_address", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "delivering_address", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "order.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "street", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "field": "street_number", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is shorter than", + "value": 2, + "message": null + } + ] + }, + { + "field": "zip_code", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 5, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "app_address", + "type": "collections", + "attributes": { + "name": "app_address", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "billing_orders_billing_address", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "billing_address", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_order.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "city", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "complete_address", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "customeraddress_address", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "address", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customeraddress.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "customers", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "addresses", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "delivering_orders_delivering_address", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "delivering_address", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_order.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "pays", + "type": "String", + "enums": null, + "defaultValue": "France", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "postal_code", + "type": [ + { + "fields": [ + { + "field": "codePostal", + "type": "String" + }, + { + "field": "codeCommune", + "type": "String" + }, + { + "field": "nomCommune", + "type": "String" + }, + { + "field": "libelleAcheminement", + "type": "String" + } + ] + } + ], + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "street", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "zip_code", + "type": "String", + "enums": null, + "defaultValue": "75009", + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is shorter than", + "value": 5, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [ + { + "id": "app_address.highOrderDelivery", + "type": "segments" + } + ] + } + } + }, + { + "id": "app_cart", + "type": "collections", + "attributes": { + "name": "app_cart", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "customer_id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "extendedcart", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "cart", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_extendedcart.cart_id", + "relationship": "HasOne", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "order", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "cart", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_order.id", + "relationship": "BelongsTo", + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [ + { + "id": "app_cart.No order", + "type": "segments" + } + ] + } + } + }, + { + "id": "app_customer", + "type": "collections", + "attributes": { + "name": "app_customer", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "Customer_blocked_customer+_from_customer", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "from_customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer_blocked_customer.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "Customer_blocked_customer+_to_customer", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "to_customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer_blocked_customer.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "TotalSpending", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "addresses", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "customers", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_address.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "age", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "avatar", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "birthday_date", + "type": "Dateonly", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "block_by_users", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "blocked_customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "blocked_customer", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "block_by_users", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "customeraddress_customer", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customeraddress.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "first_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "full_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "is_vip", + "type": "Boolean", + "enums": null, + "defaultValue": false, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "last_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "orders_customer", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_order.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "smart_billing_addresses", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_address.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "smart_carts", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_cart.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "smart_delivering_addresses", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_address.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "updated_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [ + { + "id": "app_customer.Export json", + "type": "actions" + }, + { + "id": "app_customer.Age operation", + "type": "actions" + } + ] + }, + "segments": { + "data": [ + { + "id": "app_customer.VIP customers", + "type": "segments" + }, + { + "id": "app_customer.with french address", + "type": "segments" + } + ] + } + } + }, + { + "id": "app_customer_blocked_customer", + "type": "collections", + "attributes": { + "name": "app_customer_blocked_customer", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "from_customer", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "Customer_blocked_customer+_from_customer", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "to_customer", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "Customer_blocked_customer+_to_customer", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "app_customeraddress", + "type": "collections", + "attributes": { + "name": "app_customeraddress", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "address", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "customeraddress_address", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_address.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "customer", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "customeraddress_customer", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "app_discountcart", + "type": "collections", + "attributes": { + "name": "app_discountcart", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "discount", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "extendedcart", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "discount", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_extendedcart.discount_id", + "relationship": "HasOne", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "app_extendedcart", + "type": "collections", + "attributes": { + "name": "app_extendedcart", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "cart", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "extendedcart", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_cart.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "cart_id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "color", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 20, + "message": null + } + ] + }, + { + "field": "discount", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "extendedcart", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_discountcart.id", + "relationship": "BelongsTo", + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "app_order", + "type": "collections", + "attributes": { + "name": "app_order", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "billing_address", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "billing_orders_billing_address", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_address.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "cart", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "order", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_cart.order_id", + "relationship": "HasOne", + "validations": [] + }, + { + "field": "cost", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is greater than", + "value": 0, + "message": null + }, + { + "type": "is greater than", + "value": 0, + "message": null + } + ] + }, + { + "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "customer", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "orders_customer", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "app_customer.id", + "relationship": "BelongsTo", + "validations": [] + }, + { + "field": "customer_first_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "customer_full_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "delivering_address", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "delivering_orders_delivering_address", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "app_address.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "ordered_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "ordered_date", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": false, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "status", + "type": "Enum", + "enums": [ + "PENDING", + "DISPATCHED", + "DELIVERED", + "REJECTED" + ], + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 10, + "message": null + } + ] + }, + { + "field": "updated_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [ + { + "id": "app_order.Export json", + "type": "actions" + }, + { + "id": "app_order.Refund order(s)", + "type": "actions" + } + ] + }, + "segments": { + "data": [ + { + "id": "app_order.Delivered order", + "type": "segments" + }, + { + "id": "app_order.Dispatched order", + "type": "segments" + }, + { + "id": "app_order.Pending order", + "type": "segments" + }, + { + "id": "app_order.Rejected order", + "type": "segments" + }, + { + "id": "app_order.Suspicious order", + "type": "segments" + }, + { + "id": "app_order.newly_created", + "type": "segments" + } + ] + } + } + }, + { + "id": "auth_group", + "type": "collections", + "attributes": { + "name": "auth_group", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "Group_permissions+_group", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "group", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_group_permissions.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "User_groups+_group", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "group", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user_groups.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "field": "permissions", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "group", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_permission.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "user", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "groups", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user.id", + "relationship": "BelongsToMany", + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "auth_group_permissions", + "type": "collections", + "attributes": { + "name": "auth_group_permissions", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "group", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "Group_permissions+_group", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_group.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "permission", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "Group_permissions+_permission", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_permission.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "auth_permission", + "type": "collections", + "attributes": { + "name": "auth_permission", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "Group_permissions+_permission", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "permission", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_group_permissions.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "User_user_permissions+_permission", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "permission", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user_user_permissions.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "codename", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "field": "content_type", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "permission_content_type", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "django_content_type.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "group", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "permissions", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_group.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "field": "user", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "user_permissions", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user.id", + "relationship": "BelongsToMany", + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "auth_user", + "type": "collections", + "attributes": { + "name": "auth_user", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "User_groups+_user", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "user", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user_groups.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "User_user_permissions+_user", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "user", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user_user_permissions.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "date_joined", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "email", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "field": "first_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "field": "groups", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "user", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_group.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "is_active", + "type": "Boolean", + "enums": null, + "defaultValue": true, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "is_staff", + "type": "Boolean", + "enums": null, + "defaultValue": false, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "is_superuser", + "type": "Boolean", + "enums": null, + "defaultValue": false, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "last_login", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "last_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "field": "logentry_user", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "user", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "django_admin_log.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "password", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 128, + "message": null + } + ] + }, + { + "field": "user_permissions", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "user", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_permission.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "username", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "auth_user_groups", + "type": "collections", + "attributes": { + "name": "auth_user_groups", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "group", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "User_groups+_group", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_group.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "user", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "User_groups+_user", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "auth_user_user_permissions", + "type": "collections", + "attributes": { + "name": "auth_user_user_permissions", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "permission", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "User_user_permissions+_permission", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_permission.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "user", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "User_user_permissions+_user", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "cart", + "type": "collections", + "attributes": { + "name": "cart", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "field": "order", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "flaskcart_order", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "order.id", + "relationship": "BelongsTo", + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "customer", + "type": "collections", + "attributes": { + "name": "customer", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "addresses", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "customers", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "address.id", + "relationship": "BelongsToMany", + "validations": [] + }, + { + "field": "age", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "avatar", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "birthday_date", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "first_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "field": "flaskcustomersaddresses_customer", + "type": [ + "Uuid" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "customers_addresses.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "flaskorder_customer", + "type": [ + "Uuid" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "customer", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "order.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "id", + "type": "Uuid", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 32, + "message": null + } + ] + }, + { + "field": "is_vip", + "type": "Boolean", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "last_name", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "customers_addresses", + "type": "collections", + "attributes": { + "name": "customers_addresses", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "address", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "flaskcustomersaddresses_address", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "address.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "customer", + "type": "Uuid", + "defaultValue": null, + "enums": null, + "inverseOf": "flaskcustomersaddresses_customer", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "customer.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "django_admin_log", + "type": "collections", + "attributes": { + "name": "django_admin_log", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "action_flag", + "type": "Enum", + "enums": [ + "1", + "2", + "3" + ], + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "action_time", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "change_message", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "content_type", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "logentry_content_type", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "django_content_type.id", + "relationship": "BelongsTo", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "object_id", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "object_repr", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 200, + "message": null + } + ] + }, + { + "field": "user", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "logentry_user", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": "auth_user.id", + "relationship": "BelongsTo", + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "django_content_type", + "type": "collections", + "attributes": { + "name": "django_content_type", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "app_label", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "logentry_content_type", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "content_type", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "django_admin_log.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "model", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "field": "permission_content_type", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "content_type", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "auth_permission.id", + "relationship": "HasMany", + "validations": [] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "django_session", + "type": "collections", + "attributes": { + "name": "django_session", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "expire_date", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "session_data", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "session_key", + "type": "String", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 40, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + }, + { + "id": "order", + "type": "collections", + "attributes": { + "name": "order", + "icon": null, + "integration": null, + "isReadOnly": false, + "isSearchable": true, + "isVirtual": false, + "onlyForRelationships": false, + "paginationType": "page", + "fields": [ + { + "field": "amount", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "field": "billing_address", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "flaskorder_billing_address", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "address.id", + "relationship": "BelongsTo", + "validations": [] + }, + { + "field": "created_at", + "type": "Date", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "customer", + "type": "Uuid", + "defaultValue": null, + "enums": null, + "inverseOf": "flaskorder_customer", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "customer.id", + "relationship": "BelongsTo", + "validations": [] + }, + { + "field": "delivering_address", + "type": "Number", + "defaultValue": null, + "enums": null, + "inverseOf": "order_delivering_address_set_delivering_address", + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "address.id", + "relationship": "BelongsTo", + "validations": [] + }, + { + "field": "flaskcart_order", + "type": [ + "Number" + ], + "defaultValue": null, + "enums": null, + "inverseOf": "order", + "isFilterable": false, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": "cart.id", + "relationship": "HasMany", + "validations": [] + }, + { + "field": "id", + "type": "Number", + "enums": null, + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": true, + "isReadOnly": true, + "isRequired": false, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [] + }, + { + "field": "status", + "type": "Enum", + "enums": [ + "PENDING", + "DISPATCHED", + "DELIVERED", + "REJECTED" + ], + "defaultValue": null, + "integration": null, + "inverseOf": null, + "isFilterable": true, + "isPrimaryKey": false, + "isReadOnly": false, + "isRequired": true, + "isSortable": true, + "isVirtual": false, + "reference": null, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 10, + "message": null + } + ] + } + ] + }, + "relationships": { + "actions": { + "data": [] + }, + "segments": { + "data": [] + } + } + } + ], + "included": [ + { + "id": "app_address.highOrderDelivery", + "type": "segments", + "attributes": { + "id": "app_address.highOrderDelivery", + "name": "highOrderDelivery" + } + }, + { + "id": "app_cart.No order", + "type": "segments", + "attributes": { + "id": "app_cart.No order", + "name": "No order" + } + }, + { + "id": "app_customer.Export json", + "type": "actions", + "attributes": { + "id": "app_customer-0-export json", + "name": "Export json", + "type": "bulk", + "baseUrl": null, + "endpoint": "/forest/_actions/app_customer/0/export json", + "httpMethod": "POST", + "redirect": null, + "download": true, + "fields": [], + "hooks": { + "load": false, + "change": [ + "changeHook" + ] + } + } + }, + { + "id": "app_customer.Age operation", + "type": "actions", + "attributes": { + "id": "app_customer-1-age operation", + "name": "Age operation", + "type": "single", + "baseUrl": null, + "endpoint": "/forest/_actions/app_customer/1/age operation", + "httpMethod": "POST", + "redirect": null, + "download": false, + "fields": [ + { + "field": "Loading...", + "type": "String", + "isReadOnly": true, + "defaultValue": "Form is loading", + "value": null, + "description": "", + "enums": null, + "hook": null, + "isRequired": false, + "reference": null, + "widget": null + } + ], + "hooks": { + "load": true, + "change": [ + "changeHook" + ] + } + } + }, + { + "id": "app_customer.VIP customers", + "type": "segments", + "attributes": { + "id": "app_customer.VIP customers", + "name": "VIP customers" + } + }, + { + "id": "app_customer.with french address", + "type": "segments", + "attributes": { + "id": "app_customer.with french address", + "name": "with french address" + } + }, + { + "id": "app_order.Export json", + "type": "actions", + "attributes": { + "id": "app_order-0-export json", + "name": "Export json", + "type": "global", + "baseUrl": null, + "endpoint": "/forest/_actions/app_order/0/export json", + "httpMethod": "POST", + "redirect": null, + "download": true, + "fields": [ + { + "field": "dummy field", + "value": "", + "defaultValue": "", + "description": "", + "enums": null, + "hook": null, + "isReadOnly": false, + "isRequired": false, + "reference": null, + "type": "String", + "widget": null, + "widgetEdit": null + }, + { + "field": "customer", + "value": null, + "defaultValue": null, + "description": "", + "enums": null, + "hook": null, + "isReadOnly": false, + "isRequired": true, + "reference": "app_customer.id", + "type": "Number", + "widget": null, + "widgetEdit": null + } + ], + "hooks": { + "load": false, + "change": [ + "changeHook" + ] + } + } + }, + { + "id": "app_order.Refund order(s)", + "type": "actions", + "attributes": { + "id": "app_order-1-refund order(s)", + "name": "Refund order(s)", + "type": "single", + "baseUrl": null, + "endpoint": "/forest/_actions/app_order/1/refund order(s)", + "httpMethod": "POST", + "redirect": null, + "download": false, + "fields": [ + { + "field": "reason", + "value": "", + "defaultValue": "", + "description": "", + "enums": null, + "hook": null, + "isReadOnly": false, + "isRequired": false, + "reference": null, + "type": "String", + "widget": null, + "widgetEdit": null + } + ], + "hooks": { + "load": false, + "change": [ + "changeHook" + ] + } + } + }, + { + "id": "app_order.Delivered order", + "type": "segments", + "attributes": { + "id": "app_order.Delivered order", + "name": "Delivered order" + } + }, + { + "id": "app_order.Dispatched order", + "type": "segments", + "attributes": { + "id": "app_order.Dispatched order", + "name": "Dispatched order" + } + }, + { + "id": "app_order.Pending order", + "type": "segments", + "attributes": { + "id": "app_order.Pending order", + "name": "Pending order" + } + }, + { + "id": "app_order.Rejected order", + "type": "segments", + "attributes": { + "id": "app_order.Rejected order", + "name": "Rejected order" + } + }, + { + "id": "app_order.Suspicious order", + "type": "segments", + "attributes": { + "id": "app_order.Suspicious order", + "name": "Suspicious order" + } + }, + { + "id": "app_order.newly_created", + "type": "segments", + "attributes": { + "id": "app_order.newly_created", + "name": "newly_created" + } + } + ], + "meta": { + "liana": "agent-python", + "liana_version": "1.5.6", + "stack": { + "engine": "python", + "engine_version": "3.11.3" + }, + "schemaFileHash": "94008f891a07a15668f272455796cec49a8c8526" + } +} \ No newline at end of file diff --git a/src/_example/django/django_demo/.forestadmin-schema_v2.json b/src/_example/django/django_demo/.forestadmin-schema_v2.json new file mode 100644 index 000000000..0901215de --- /dev/null +++ b/src/_example/django/django_demo/.forestadmin-schema_v2.json @@ -0,0 +1,3429 @@ +{ + "collections": [ + { + "name": "address", + "fields": [ + { + "name": "city", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "country", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "street", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "street_number", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is shorter than", + "value": 2, + "message": null + } + ] + }, + { + "name": "zip_code", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 5, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "customers", + "type": "ManyToMany", + "foreignCollection": "customer", + "throughCollection": "customers_addresses", + "originKey": "address_id", + "originKeyTarget": "id", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "flaskcustomersaddresses_address", + "type": "OneToMany", + "foreignCollection": "customers_addresses", + "originKey": "address_id", + "originKeyTarget": "id" + }, + { + "name": "flaskorder_billing_address", + "type": "OneToMany", + "foreignCollection": "order", + "originKey": "billing_address_id", + "originKeyTarget": "id" + }, + { + "name": "order_delivering_address_set_delivering_address", + "type": "OneToMany", + "foreignCollection": "order", + "originKey": "delivering_address_id", + "originKeyTarget": "id" + } + ] + }, + { + "name": "app_address", + "fields": [ + { + "name": "city", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "complete_address", + "type": "String", + "filterOperators": [], + "isWritable": false + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "pays", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "prefillFormValue": "France", + "validations": [ + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "postal_code", + "type": [ + { + "fields": [ + { + "field": "codePostal", + "type": "String" + }, + { + "field": "codeCommune", + "type": "String" + }, + { + "field": "nomCommune", + "type": "String" + }, + { + "field": "libelleAcheminement", + "type": "String" + } + ] + } + ], + "filterOperators": [], + "isSortable": false, + "isWritable": false + }, + { + "name": "street", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "zip_code", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "prefillFormValue": "75009", + "validations": [ + { + "type": "is shorter than", + "value": 5, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "billing_orders_billing_address", + "type": "OneToMany", + "foreignCollection": "app_order", + "originKey": "billing_address_id", + "originKeyTarget": "id" + }, + { + "name": "customeraddress_address", + "type": "OneToMany", + "foreignCollection": "app_customeraddress", + "originKey": "address_id", + "originKeyTarget": "id" + }, + { + "name": "customers", + "type": "ManyToMany", + "foreignCollection": "app_customer", + "throughCollection": "app_customeraddress", + "originKey": "address_id", + "originKeyTarget": "id", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "delivering_orders_delivering_address", + "type": "OneToMany", + "foreignCollection": "app_order", + "originKey": "delivering_address_id", + "originKeyTarget": "id" + } + ], + "segments": [ + { + "id": "app_address.highOrderDelivery", + "name": "highOrderDelivery" + } + ], + "canCount": false + }, + { + "name": "app_cart", + "fields": [ + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "isWritable": false + }, + { + "name": "customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "IncludesAll", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isSortable": false, + "isWritable": false + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "order_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + } + ], + "relations": [ + { + "name": "extendedcart", + "type": "OneToOne", + "foreignCollection": "app_extendedcart", + "originKey": "cart_id", + "originKeyTarget": "id" + }, + { + "name": "order", + "type": "ManyToOne", + "foreignCollection": "app_order", + "foreignKey": "order_id", + "foreignKeyTarget": "id" + } + ], + "segments": [ + { + "id": "app_cart.No order", + "name": "No order" + } + ] + }, + { + "name": "app_customer", + "fields": [ + { + "name": "TotalSpending", + "type": "Number", + "filterOperators": [], + "isSortable": false, + "isWritable": false + }, + { + "name": "age", + "type": "Number", + "filterOperators": [], + "isSortable": false, + "isWritable": false + }, + { + "name": "avatar", + "type": "String", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "birthday_date", + "type": "Dateonly", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "isWritable": false + }, + { + "name": "first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "full_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "GreaterThan", + "In", + "IncludesAll", + "LessThan", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "isSortable": false + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "is_vip", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "prefillFormValue": false + }, + { + "name": "last_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "updated_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "isWritable": false + } + ], + "relations": [ + { + "name": "Customer_blocked_customer+_from_customer", + "type": "OneToMany", + "foreignCollection": "app_customer_blocked_customer", + "originKey": "from_customer_id", + "originKeyTarget": "id" + }, + { + "name": "Customer_blocked_customer+_to_customer", + "type": "OneToMany", + "foreignCollection": "app_customer_blocked_customer", + "originKey": "to_customer_id", + "originKeyTarget": "id" + }, + { + "name": "addresses", + "type": "ManyToMany", + "foreignCollection": "app_address", + "throughCollection": "app_customeraddress", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "block_by_users", + "type": "ManyToMany", + "foreignCollection": "app_customer", + "throughCollection": "app_customer_blocked_customer", + "originKey": "to_customer_id", + "originKeyTarget": "id", + "foreignKey": "from_customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "blocked_customer", + "type": "ManyToMany", + "foreignCollection": "app_customer", + "throughCollection": "app_customer_blocked_customer", + "originKey": "from_customer_id", + "originKeyTarget": "id", + "foreignKey": "to_customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "customeraddress_customer", + "type": "OneToMany", + "foreignCollection": "app_customeraddress", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "orders_customer", + "type": "OneToMany", + "foreignCollection": "app_order", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "smart_billing_addresses", + "type": "ManyToMany", + "foreignCollection": "app_address", + "throughCollection": "app_order", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "billing_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "smart_carts", + "type": "OneToMany", + "foreignCollection": "app_cart", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "smart_delivering_addresses", + "type": "ManyToMany", + "foreignCollection": "app_address", + "throughCollection": "app_order", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "delivering_address_id", + "foreignKeyTarget": "id" + } + ], + "actions": [ + { + "id": "app_customer-0-export json", + "name": "Export json", + "scope": "bulk", + "endpoint": "/forest/_actions/app_customer/0/export json", + "download": true + }, + { + "id": "app_customer-1-age operation", + "name": "Age operation", + "scope": "single", + "endpoint": "/forest/_actions/app_customer/1/age operation", + "isDynamicForm": true + } + ], + "segments": [ + { + "id": "app_customer.VIP customers", + "name": "VIP customers" + }, + { + "id": "app_customer.with french address", + "name": "with french address" + } + ] + }, + { + "name": "app_customer_blocked_customer", + "fields": [ + { + "name": "from_customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "to_customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "from_customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "from_customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "to_customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "to_customer_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "app_customeraddress", + "fields": [ + { + "name": "address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + } + ], + "relations": [ + { + "name": "address", + "type": "ManyToOne", + "foreignCollection": "app_address", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "app_discountcart", + "fields": [ + { + "name": "discount", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + } + ], + "relations": [ + { + "name": "extendedcart", + "type": "OneToOne", + "foreignCollection": "app_extendedcart", + "originKey": "discount_id", + "originKeyTarget": "id" + } + ] + }, + { + "name": "app_extendedcart", + "fields": [ + { + "name": "cart_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "color", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 20, + "message": null + } + ] + }, + { + "name": "discount_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + } + ], + "relations": [ + { + "name": "cart", + "type": "ManyToOne", + "foreignCollection": "app_cart", + "foreignKey": "cart_id", + "foreignKeyTarget": "id" + }, + { + "name": "discount", + "type": "ManyToOne", + "foreignCollection": "app_discountcart", + "foreignKey": "discount_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "app_order", + "fields": [ + { + "name": "billing_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "cost", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is greater than", + "value": 0, + "message": null + }, + { + "type": "is greater than", + "value": 0, + "message": null + } + ] + }, + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "isWritable": false + }, + { + "name": "customer_first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ] + }, + { + "name": "customer_full_name", + "type": "String", + "filterOperators": [], + "isSortable": false, + "isWritable": false + }, + { + "name": "customer_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "delivering_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "ordered_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "ordered_date", + "type": "Date", + "filterOperators": [], + "isSortable": false, + "isWritable": false + }, + { + "name": "status", + "type": "Enum", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": [ + "PENDING", + "DISPATCHED", + "DELIVERED", + "REJECTED" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 10, + "message": null + } + ] + }, + { + "name": "updated_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "isWritable": false + } + ], + "relations": [ + { + "name": "billing_address", + "type": "ManyToOne", + "foreignCollection": "app_address", + "foreignKey": "billing_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "cart", + "type": "OneToOne", + "foreignCollection": "app_cart", + "originKey": "order_id", + "originKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "app_customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "delivering_address", + "type": "ManyToOne", + "foreignCollection": "app_address", + "foreignKey": "delivering_address_id", + "foreignKeyTarget": "id" + } + ], + "actions": [ + { + "id": "app_order-0-export json", + "name": "Export json", + "scope": "global", + "endpoint": "/forest/_actions/app_order/0/export json", + "download": true, + "fields": [ + { + "name": "dummy field", + "type": "String", + "value": "", + "prefillValue": "" + }, + { + "name": "customer", + "type": "Number", + "isRequired": true, + "reference": "app_customer.id" + } + ] + }, + { + "id": "app_order-1-refund order(s)", + "name": "Refund order(s)", + "scope": "single", + "endpoint": "/forest/_actions/app_order/1/refund order(s)", + "fields": [ + { + "name": "reason", + "type": "String", + "value": "", + "prefillValue": "" + } + ] + } + ], + "segments": [ + { + "id": "app_order.Delivered order", + "name": "Delivered order" + }, + { + "id": "app_order.Dispatched order", + "name": "Dispatched order" + }, + { + "id": "app_order.Pending order", + "name": "Pending order" + }, + { + "id": "app_order.Rejected order", + "name": "Rejected order" + }, + { + "id": "app_order.Suspicious order", + "name": "Suspicious order" + }, + { + "id": "app_order.newly_created", + "name": "newly_created" + } + ] + }, + { + "name": "auth_group", + "fields": [ + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "Group_permissions+_group", + "type": "OneToMany", + "foreignCollection": "auth_group_permissions", + "originKey": "group_id", + "originKeyTarget": "id" + }, + { + "name": "User_groups+_group", + "type": "OneToMany", + "foreignCollection": "auth_user_groups", + "originKey": "group_id", + "originKeyTarget": "id" + }, + { + "name": "permissions", + "type": "ManyToMany", + "foreignCollection": "auth_permission", + "throughCollection": "auth_group_permissions", + "originKey": "group_id", + "originKeyTarget": "id", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToMany", + "foreignCollection": "auth_user", + "throughCollection": "auth_user_groups", + "originKey": "group_id", + "originKeyTarget": "id", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "auth_group_permissions", + "fields": [ + { + "name": "group_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "permission_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "group", + "type": "ManyToOne", + "foreignCollection": "auth_group", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "permission", + "type": "ManyToOne", + "foreignCollection": "auth_permission", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "auth_permission", + "fields": [ + { + "name": "codename", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "name": "content_type_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "Group_permissions+_permission", + "type": "OneToMany", + "foreignCollection": "auth_group_permissions", + "originKey": "permission_id", + "originKeyTarget": "id" + }, + { + "name": "User_user_permissions+_permission", + "type": "OneToMany", + "foreignCollection": "auth_user_user_permissions", + "originKey": "permission_id", + "originKeyTarget": "id" + }, + { + "name": "content_type", + "type": "ManyToOne", + "foreignCollection": "django_content_type", + "foreignKey": "content_type_id", + "foreignKeyTarget": "id" + }, + { + "name": "group", + "type": "ManyToMany", + "foreignCollection": "auth_group", + "throughCollection": "auth_group_permissions", + "originKey": "permission_id", + "originKeyTarget": "id", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToMany", + "foreignCollection": "auth_user", + "throughCollection": "auth_user_user_permissions", + "originKey": "permission_id", + "originKeyTarget": "id", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "auth_user", + "fields": [ + { + "name": "date_joined", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "email", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is shorter than", + "value": 254, + "message": null + } + ] + }, + { + "name": "first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "is_active", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "prefillFormValue": true + }, + { + "name": "is_staff", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "prefillFormValue": false + }, + { + "name": "is_superuser", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "prefillFormValue": false + }, + { + "name": "last_login", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "last_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + }, + { + "name": "password", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 128, + "message": null + } + ] + }, + { + "name": "username", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 150, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "User_groups+_user", + "type": "OneToMany", + "foreignCollection": "auth_user_groups", + "originKey": "user_id", + "originKeyTarget": "id" + }, + { + "name": "User_user_permissions+_user", + "type": "OneToMany", + "foreignCollection": "auth_user_user_permissions", + "originKey": "user_id", + "originKeyTarget": "id" + }, + { + "name": "groups", + "type": "ManyToMany", + "foreignCollection": "auth_group", + "throughCollection": "auth_user_groups", + "originKey": "user_id", + "originKeyTarget": "id", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "logentry_user", + "type": "OneToMany", + "foreignCollection": "django_admin_log", + "originKey": "user_id", + "originKeyTarget": "id" + }, + { + "name": "user_permissions", + "type": "ManyToMany", + "foreignCollection": "auth_permission", + "throughCollection": "auth_user_user_permissions", + "originKey": "user_id", + "originKeyTarget": "id", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "auth_user_groups", + "fields": [ + { + "name": "group_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "user_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "group", + "type": "ManyToOne", + "foreignCollection": "auth_group", + "foreignKey": "group_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToOne", + "foreignCollection": "auth_user", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "auth_user_user_permissions", + "fields": [ + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "permission_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "user_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "permission", + "type": "ManyToOne", + "foreignCollection": "auth_permission", + "foreignKey": "permission_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToOne", + "foreignCollection": "auth_user", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "cart", + "fields": [ + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "order_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + } + ], + "relations": [ + { + "name": "order", + "type": "ManyToOne", + "foreignCollection": "order", + "foreignKey": "order_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "customer", + "fields": [ + { + "name": "age", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "avatar", + "type": "String", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "birthday_date", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "first_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + }, + { + "name": "id", + "type": "Uuid", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "Missing", + "NotEqual", + "NotIn", + "Present", + "StartsWith" + ], + "isPrimaryKey": true, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 32, + "message": null + } + ] + }, + { + "name": "is_vip", + "type": "Boolean", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "last_name", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 255, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "addresses", + "type": "ManyToMany", + "foreignCollection": "address", + "throughCollection": "customers_addresses", + "originKey": "customer_id", + "originKeyTarget": "id", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "flaskcustomersaddresses_customer", + "type": "OneToMany", + "foreignCollection": "customers_addresses", + "originKey": "customer_id", + "originKeyTarget": "id" + }, + { + "name": "flaskorder_customer", + "type": "OneToMany", + "foreignCollection": "order", + "originKey": "customer_id", + "originKeyTarget": "id" + } + ] + }, + { + "name": "customers_addresses", + "fields": [ + { + "name": "address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "customer_id", + "type": "Uuid", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "Missing", + "NotEqual", + "NotIn", + "Present", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + } + ], + "relations": [ + { + "name": "address", + "type": "ManyToOne", + "foreignCollection": "address", + "foreignKey": "address_id", + "foreignKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "django_admin_log", + "fields": [ + { + "name": "action_flag", + "type": "Enum", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": [ + "1", + "2", + "3" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "action_time", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "change_message", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ] + }, + { + "name": "content_type_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "object_id", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ] + }, + { + "name": "object_repr", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 200, + "message": null + } + ] + }, + { + "name": "user_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "content_type", + "type": "ManyToOne", + "foreignCollection": "django_content_type", + "foreignKey": "content_type_id", + "foreignKeyTarget": "id" + }, + { + "name": "user", + "type": "ManyToOne", + "foreignCollection": "auth_user", + "foreignKey": "user_id", + "foreignKeyTarget": "id" + } + ] + }, + { + "name": "django_content_type", + "fields": [ + { + "name": "app_label", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "model", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 100, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "logentry_content_type", + "type": "OneToMany", + "foreignCollection": "django_admin_log", + "originKey": "content_type_id", + "originKeyTarget": "id" + }, + { + "name": "permission_content_type", + "type": "OneToMany", + "foreignCollection": "auth_permission", + "originKey": "content_type_id", + "originKeyTarget": "id" + } + ] + }, + { + "name": "django_session", + "fields": [ + { + "name": "expire_date", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "session_data", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "session_key", + "type": "String", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "LongerThan", + "Missing", + "NotContains", + "NotEqual", + "NotIn", + "Present", + "ShorterThan", + "StartsWith" + ], + "isPrimaryKey": true, + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 40, + "message": null + } + ] + } + ] + }, + { + "name": "order", + "fields": [ + { + "name": "amount", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + } + ] + }, + { + "name": "billing_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "created_at", + "type": "Date", + "filterOperators": [ + "After", + "AfterXHoursAgo", + "Before", + "BeforeXHoursAgo", + "Blank", + "Equal", + "Future", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Past", + "Present", + "PreviousMonth", + "PreviousMonthToDate", + "PreviousQuarter", + "PreviousQuarterToDate", + "PreviousWeek", + "PreviousWeekToDate", + "PreviousXDays", + "PreviousXDaysToDate", + "PreviousYear", + "PreviousYearToDate", + "Today", + "Yesterday" + ] + }, + { + "name": "customer_id", + "type": "Uuid", + "filterOperators": [ + "Blank", + "Contains", + "EndsWith", + "Equal", + "In", + "Like", + "Missing", + "NotEqual", + "NotIn", + "Present", + "StartsWith" + ] + }, + { + "name": "delivering_address_id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ] + }, + { + "name": "id", + "type": "Number", + "filterOperators": [ + "Blank", + "Equal", + "GreaterThan", + "In", + "LessThan", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "isPrimaryKey": true, + "isWritable": false + }, + { + "name": "status", + "type": "Enum", + "filterOperators": [ + "Blank", + "Equal", + "In", + "Missing", + "NotEqual", + "NotIn", + "Present" + ], + "enumerations": [ + "PENDING", + "DISPATCHED", + "DELIVERED", + "REJECTED" + ], + "validations": [ + { + "type": "is present", + "value": null, + "message": null + }, + { + "type": "is shorter than", + "value": 10, + "message": null + } + ] + } + ], + "relations": [ + { + "name": "billing_address", + "type": "ManyToOne", + "foreignCollection": "address", + "foreignKey": "billing_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "customer", + "type": "ManyToOne", + "foreignCollection": "customer", + "foreignKey": "customer_id", + "foreignKeyTarget": "id" + }, + { + "name": "delivering_address", + "type": "ManyToOne", + "foreignCollection": "address", + "foreignKey": "delivering_address_id", + "foreignKeyTarget": "id" + }, + { + "name": "flaskcart_order", + "type": "OneToMany", + "foreignCollection": "cart", + "originKey": "order_id", + "originKeyTarget": "id" + } + ] + } + ], + "meta": { + "agent": "agent-python", + "agent_version": "1.5.5", + "stack": { + "engine": "python", + "engine_version": "3.10.11" + }, + "datasources": [ + { + "name": "DjangoDatasource", + "version": "1.5.5", + "django_version": "4.2.11" + } + ] + } +} \ No newline at end of file diff --git a/src/_example/django/django_demo/app/flask_models.py b/src/_example/django/django_demo/app/flask_models.py index 367c56a13..01dc28a17 100644 --- a/src/_example/django/django_demo/app/flask_models.py +++ b/src/_example/django/django_demo/app/flask_models.py @@ -23,7 +23,7 @@ class Meta: class FlaskCustomer(models.Model): - id = models.BinaryField(primary_key=True, db_column="pk") + id = models.UUIDField(primary_key=True, db_column="pk") first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) birthday_date = models.DateTimeField(blank=True, null=True) diff --git a/src/_example/django/django_demo/app/forest_admin.py b/src/_example/django/django_demo/app/forest_admin.py index c9444d925..04c566f13 100644 --- a/src/_example/django/django_demo/app/forest_admin.py +++ b/src/_example/django/django_demo/app/forest_admin.py @@ -33,8 +33,8 @@ refund_order_action, rejected_order_segment, suspicious_order_segment, + total_order_chart, ) -from demo.forest_admin.smart.order import total_order_chart from forestadmin.datasource_toolkit.interfaces.query.condition_tree.nodes.leaf import ConditionTreeLeaf from forestadmin.django_agent.agent import DjangoAgent @@ -102,7 +102,7 @@ def customize_forest(agent: DjangoAgent): }, ).add_segment("with french address", french_address_segment).add_segment( "VIP customers", - lambda context: ConditionTreeLeaf("is_vip", "equal", True) + lambda context: ConditionTreeLeaf("is_vip", "equal", True), # add actions ).add_action( "Export json", export_json_action_dict diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/agent.py b/src/agent_toolkit/forestadmin/agent_toolkit/agent.py index 0c65e8859..224508306 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/agent.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/agent.py @@ -16,6 +16,7 @@ from forestadmin.agent_toolkit.services.serializers.json_api import create_json_api_schema from forestadmin.agent_toolkit.utils.context import HttpResponseBuilder from forestadmin.agent_toolkit.utils.forest_schema.emitter import SchemaEmitter +from forestadmin.agent_toolkit.utils.forest_schema.emitter_v2 import SchemaEmitterV2 from forestadmin.agent_toolkit.utils.forest_schema.type import AgentMeta from forestadmin.agent_toolkit.utils.http import ForestHttpApi from forestadmin.datasource_toolkit.datasource_customizer.collection_customizer import CollectionCustomizer @@ -199,17 +200,22 @@ async def _start(self): ForestLogger.log("debug", "Starting agent") if self.options["skip_schema_update"] is False: + # try: + # api_map = await SchemaEmitter.get_serialized_schema( + # self.options, await self.customizer.get_datasource(), self.meta + # ) + # await ForestHttpApi.send_schema(self.options, api_map) + # except Exception: + # ForestLogger.log("exception", "Error generating/sending forest schema V1") + try: - api_map = await SchemaEmitter.get_serialized_schema( + api_map = await SchemaEmitterV2.get_serialized_schema( self.options, await self.customizer.get_datasource(), self.meta ) + await ForestHttpApi.send_schema_v2(self.options, api_map) except Exception: - ForestLogger.log("exception", "Error generating forest schema") + ForestLogger.log("exception", "Error generating/sending forest schema V2") - try: - await ForestHttpApi.send_schema(self.options, api_map) - except Exception: - ForestLogger.log("warning", "Cannot send the apimap to Forest. Are you online?") else: ForestLogger.log("warning", 'Schema update was skipped (caused by options["skip_schema_update"]=True)') diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter.py index a7cf77ef8..bf813aaea 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter.py @@ -78,7 +78,10 @@ async def get_serialized_schema( ) raise - return cls.serialize(collections_schema, meta) + serialized = cls.serialize(collections_schema, meta) + with open(f'{options["schema_path"].split(".json")[0]}_json_api.json', "w") as fout: + json.dump(serialized, fout, indent=4) + return serialized @staticmethod async def generate( diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter_v2.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter_v2.py new file mode 100644 index 000000000..f0ec55041 --- /dev/null +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/emitter_v2.py @@ -0,0 +1,103 @@ +import json +from hashlib import sha1 +from typing import Any, Dict, List, Union + +from forestadmin.agent_toolkit.forest_logger import ForestLogger +from forestadmin.agent_toolkit.options import Options +from forestadmin.agent_toolkit.utils.forest_schema.generator_collection_v2 import SchemaCollectionGeneratorV2 +from forestadmin.agent_toolkit.utils.forest_schema.type import AgentMeta +from forestadmin.agent_toolkit.utils.forest_schema.type_v2 import ( + AgentMetaV2, + SchemaV2Collection, + template_reduce_collection, +) +from forestadmin.datasource_toolkit.collections import Collection +from forestadmin.datasource_toolkit.datasource_customizer.datasource_customizer import DatasourceCustomizer +from forestadmin.datasource_toolkit.datasources import Datasource +from forestadmin.datasource_toolkit.decorators.collection_decorator import CollectionDecorator + + +class SchemaEmitterV2: + @classmethod + def serialize( + cls, + collections: List[SchemaV2Collection], + meta: AgentMetaV2, + ) -> Dict[str, Any]: + """return schema ready to send as api_map format""" + schema_file_hash = sha1(json.dumps({"collections": collections, "meta": meta}).encode("utf-8")).hexdigest() + return { + "collections": collections, + "meta": { + **meta, + "schemaFileHash": schema_file_hash, + }, + } + + @classmethod + def generate_meta( + cls, + meta: AgentMeta, + datasource: Union[Datasource[Collection], DatasourceCustomizer], + ) -> AgentMetaV2: + used_datasources = set([_get_base_datasource(col) for col in datasource.collections]) + + return { + "agent": meta["liana"], + "agent_version": meta["liana_version"], + "stack": meta["stack"], + "datasources": [d.mk_meta_entry() for d in used_datasources], + } + + @classmethod + async def get_serialized_schema( + cls, options: Options, datasource: Union[Datasource[Collection], DatasourceCustomizer], meta: AgentMeta + ): + meta_v2 = cls.generate_meta(meta, datasource) + schema_path = f'{options["schema_path"].split(".json")[0]}_v2.json' + full_schema_path = f'{options["schema_path"].split(".json")[0]}_full_v2.json' + if not options["is_production"]: + collections_schema = await SchemaEmitterV2.generate(options["prefix"], datasource) + + with open(full_schema_path, "w", encoding="utf-8") as schema_file: + json.dump({"collections": collections_schema, "meta": meta_v2}, schema_file, indent=4) + + reduced_collections = [] + for collection in collections_schema: + reduced_collections.append(template_reduce_collection(collection)) + collections_schema = reduced_collections + with open(schema_path, "w", encoding="utf-8") as schema_file: + json.dump({"collections": reduced_collections, "meta": meta_v2}, schema_file, indent=4) + else: + 1 / 0 + try: + with open(schema_path, "r", encoding="utf-8") as schema_file: + collections_schema = json.load(schema_file)["collections"] + + except Exception: + ForestLogger.log( + "error", + f"Can't read {options['schema_path']}. Providing a schema is mandatory in production. Skipping...", + ) + raise + + return cls.serialize(collections_schema, meta_v2) + + @staticmethod + async def generate( + prefix: str, datasource: Union[Datasource[Collection], DatasourceCustomizer] + ) -> List[SchemaV2Collection]: + """generate schema from datasource""" + collection_schema: List[SchemaV2Collection] = [] + for collection in datasource.collections: + collection_schema.append(await SchemaCollectionGeneratorV2.build(prefix, collection)) # type:ignore + return sorted(collection_schema, key=lambda collection: collection["name"]) + + +def _get_base_datasource(input_collection: Collection) -> Datasource: + collection = input_collection + + while isinstance(collection, CollectionDecorator): + collection = collection.child_collection + + return collection.datasource # type:ignore diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_action_v2.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_action_v2.py new file mode 100644 index 000000000..f30f7421f --- /dev/null +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_action_v2.py @@ -0,0 +1,87 @@ +from typing import List, Union, cast + +from forestadmin.agent_toolkit.utils.forest_schema.action_values import ForestValueConverter +from forestadmin.agent_toolkit.utils.forest_schema.generator_action_field_widget import GeneratorActionFieldWidget +from forestadmin.agent_toolkit.utils.forest_schema.generator_field_v2 import SchemaFieldGeneratorV2 +from forestadmin.agent_toolkit.utils.forest_schema.type_v2 import SchemaV2Action, SchemaV2ActionField +from forestadmin.datasource_toolkit.collections import Collection +from forestadmin.datasource_toolkit.datasource_customizer.collection_customizer import CollectionCustomizer +from forestadmin.datasource_toolkit.datasources import Datasource +from forestadmin.datasource_toolkit.interfaces.actions import Action, ActionField, ActionFieldType +from forestadmin.datasource_toolkit.interfaces.fields import Column, PrimitiveType +from forestadmin.datasource_toolkit.utils.schema import SchemaUtils + + +class SchemaActionGeneratorV2: + @classmethod + async def build(cls, prefix: str, collection: Union[Collection, CollectionCustomizer], name: str) -> SchemaV2Action: + schema = collection.schema["actions"][name] + idx = list(collection.schema["actions"].keys()).index(name) + slug = name.lower().replace(r"[^a-z0-9-]+", "-") + ret = SchemaV2Action( + id=f"{collection.name}-{idx}-{slug}", # type:ignore + name=name, + scope=schema.scope.value.lower(), # type:ignore + endpoint=f"/forest/_actions/{collection.name}/{idx}/{slug}", # type:ignore + download=bool(schema.generate_file), + isDynamicForm=not schema.static_form, + ) + if schema.static_form: + ret["fields"] = await cls.build_fields(collection, schema, name) + + return ret + + @classmethod + async def build_field_schema(cls, datasource: Datasource[Collection], field: ActionField) -> SchemaV2ActionField: + value = ForestValueConverter.value_to_forest(field, field.get("value")) + default_value = ForestValueConverter.value_to_forest(field, field.get("default_value")) + output: SchemaV2ActionField = { + "name": field["label"], + "type": field["type"], + "description": field.get("description"), + # When sending to server, we need to rename 'value' into 'defaultValue' + # otherwise, it does not gets applied 🤷‍♂️ + "value": value, + "prefillValue": default_value, + # "enumeration": None, # default value + "isReadOnly": ( + field["is_read_only"] if "is_read_only" in field and field["is_read_only"] is not None else False + ), + "isRequired": ( + field["is_required"] if "is_required" in field and field["is_required"] is not None else True + ), + # "reference": None, # default value + "widget": GeneratorActionFieldWidget.build_widget_options(field), + } + if field["type"] == ActionFieldType.COLLECTION: + collection: Collection = datasource.get_collection(field["collection_name"]) # type: ignore + pk = SchemaUtils.get_primary_keys(collection.schema)[0] + pk_schema = cast(Column, collection.get_field(pk)) + output["type"] = SchemaFieldGeneratorV2.build_column_type(pk_schema["column_type"]) # type: ignore + output["reference"] = f"{collection.name}.{pk}" + + elif "File" in field["type"].value: + output["type"] = ["File"] if "List" in field["type"].value else "File" # type: ignore + + elif field["type"].value.endswith("List"): + output["type"] = [PrimitiveType(field["type"].value[:-4])] # type: ignore + else: + output["type"] = field["type"].value # type: ignore + + if field["type"] in [ActionFieldType.ENUM, ActionFieldType.ENUM_LIST]: + output["enumeration"] = field.get("enum_values") + + if not isinstance(output["type"], str): + output["type"] = SchemaFieldGeneratorV2.build_column_type(output["type"]) # type: ignore + + return SchemaV2ActionField(**output) + + @classmethod + async def build_fields( + cls, collection: Union[Collection, CollectionCustomizer], action: Action, name: str + ) -> List[SchemaV2ActionField]: + fields = await collection.get_form(None, name, None, None) # type:ignore + new_fields: List[SchemaV2ActionField] = [] + for field in fields: + new_fields.append(await cls.build_field_schema(collection.datasource, field)) # type:ignore + return new_fields diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection.py index 9083fff4f..24d920c49 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection.py @@ -25,16 +25,16 @@ async def build(prefix: str, collection: Union[Collection, CollectionCustomizer] return { "name": collection.name, - "isVirtual": False, "icon": None, + "integration": None, "isReadOnly": all( [f["type"] == FieldType.COLUMN and f["is_read_only"] for f in collection.schema["fields"].values()] ), - "integration": None, "isSearchable": collection.schema["searchable"], + "isVirtual": False, "onlyForRelationships": False, "paginationType": "page", - "searchField": None, + # "searchField": None, "actions": sorted( [ await SchemaActionGenerator.build(prefix, collection, name) diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection_v2.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection_v2.py new file mode 100644 index 000000000..4a1f4445b --- /dev/null +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_collection_v2.py @@ -0,0 +1,47 @@ +from typing import List + +from forestadmin.agent_toolkit.utils.forest_schema.generator_action_v2 import SchemaActionGeneratorV2 +from forestadmin.agent_toolkit.utils.forest_schema.generator_field_v2 import SchemaFieldGeneratorV2 +from forestadmin.agent_toolkit.utils.forest_schema.generator_segment import SchemaSegmentGenerator +from forestadmin.agent_toolkit.utils.forest_schema.type_v2 import SchemaV2Collection, SchemaV2Field, SchemaV2Relation +from forestadmin.datasource_toolkit.collections import Collection +from forestadmin.datasource_toolkit.interfaces.fields import is_column + + +class SchemaCollectionGeneratorV2: + @staticmethod + async def build(prefix: str, collection: Collection) -> SchemaV2Collection: + fields: List[SchemaV2Field] = [] + relations: List[SchemaV2Relation] = [] + for field_name in collection.schema["fields"].keys(): + field_schema = collection.get_field(field_name) + if is_column(field_schema): + fields.append(SchemaFieldGeneratorV2.build_field(collection, field_name)) + else: + relations.append(SchemaFieldGeneratorV2.build_relation(collection, field_name)) + + return { + "name": collection.name, + "fields": sorted(fields, key=lambda field: field["name"]), + "relations": sorted(relations, key=lambda field: field["name"]), + "actions": sorted( + [ + await SchemaActionGeneratorV2.build(prefix, collection, name) + for name in collection.schema["actions"].keys() + ], + key=lambda action: action["id"], + ), + "segments": sorted( + [await SchemaSegmentGenerator.build(collection, name) for name in collection.schema["segments"]], + key=lambda segment: segment["id"], + ), + # capabilities + "canSearch": collection.schema["searchable"], + "canList": collection.schema["listable"], + "canCreate": collection.schema["creatable"], + "canUpdate": collection.schema["updatable"], + "canDelete": collection.schema["deletable"], + "canCount": collection.schema["countable"], + "canChart": collection.schema["chartable"], + "canNativeQuery": collection.schema["support_native_query"], + } diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field.py index 12f6228f4..b826b8981 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field.py @@ -50,7 +50,7 @@ def build(cls, collection: Union[Collection, CollectionCustomizer], field_name: schema = cls.build_relation_schema(collection, field_name, field_schema) else: raise - return cast(ForestServerField, dict(sorted(schema.items()))) + return schema @staticmethod def build_column_type(_column_type: ColumnAlias) -> ColumnAlias: @@ -81,21 +81,21 @@ def build_column_schema(cls, name: str, collection: Collection) -> ForestServerF res = { "field": name, "type": cls.build_column_type(column["column_type"]), - "validations": FrontendValidationUtils.convert_validation_list(column["validations"]), - "defaultValue": column["default_value"], "enums": column["enum_values"], + "defaultValue": column["default_value"], "integration": None, "inverseOf": None, "isFilterable": FrontendFilterableUtils.is_filterable(column["column_type"], column["filter_operators"]), "isPrimaryKey": bool(column["is_primary_key"]), - "isSortable": bool(column["is_sortable"]), # When a column is a foreign key, it is readonly. # This may sound counter-intuitive: it is so that the user don't have two fields which # allow updating the same foreign key in the detail-view form (fk + many to one) "isReadOnly": is_foreign_key or bool(column["is_read_only"]), "isRequired": any([v["operator"] == Operator.PRESENT for v in validations]), + "isSortable": bool(column["is_sortable"]), "isVirtual": False, "reference": None, + "validations": FrontendValidationUtils.convert_validation_list(column["validations"]), } return ForestServerField(**res) @@ -123,11 +123,11 @@ def build_one_to_one_schema( "defaultValue": None, "isFilterable": cls.is_foreign_collection_filterable(foreign_collection), "isPrimaryKey": False, - "isRequired": False, "isReadOnly": bool(key_field["is_read_only"]), + "isRequired": False, "isSortable": bool(target_field["is_sortable"]), - "validations": [], "reference": f"{foreign_collection.name}.{relation['origin_key']}", + "validations": [], } @classmethod @@ -202,4 +202,4 @@ def build_relation_schema( res = cls.build_many_to_one_schema( cast(ManyToOne, field_schema), collection, foreign_collection, relation_schema ) - return res + return {"field": res["field"], "type": res["type"], **dict(sorted(res.items()))} diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field_v2.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field_v2.py new file mode 100644 index 000000000..59a92af97 --- /dev/null +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/generator_field_v2.py @@ -0,0 +1,123 @@ +from typing import cast + +from forestadmin.agent_toolkit.utils.forest_schema.type_v2 import SchemaV2Field, SchemaV2Relation +from forestadmin.agent_toolkit.utils.forest_schema.validation import FrontendValidationUtils +from forestadmin.datasource_toolkit.collections import Collection +from forestadmin.datasource_toolkit.interfaces.fields import ( + Column, + ColumnAlias, + ManyToMany, + ManyToOne, + OneToMany, + OneToOne, + Operator, + PrimitiveType, + RelationAlias, + is_many_to_many, + is_many_to_one, + is_one_to_many, + is_one_to_one, +) + + +class SchemaFieldGeneratorV2: + @classmethod + def _convert_operator(cls, operator: Operator) -> str: + return operator.value.replace("_", " ").title().replace(" ", "") + + @classmethod + def build_field(cls, collection: Collection, field_name: str) -> SchemaV2Field: + field_schema: Column = cast(Column, collection.get_field(field_name)) + return { + "name": field_name, + "type": cls.build_column_type(field_schema["column_type"]), + "filterOperators": sorted( + [ + SchemaFieldGeneratorV2._convert_operator(operator) + for operator in field_schema["filter_operators"] or {} + ] + ), + "enumerations": ( + field_schema["enum_values"] if field_schema["enum_values"] is not None else [] + ), # type:ignore + "isPrimaryKey": field_schema["is_primary_key"], + "isSortable": field_schema["is_sortable"], + "isWritable": not field_schema["is_read_only"], + "prefillFormValue": field_schema["default_value"], + "validations": FrontendValidationUtils.convert_validation_list(field_schema["validations"]), + } + + @staticmethod + def build_column_type(_column_type: ColumnAlias) -> ColumnAlias: + column_type: ColumnAlias + if isinstance(_column_type, PrimitiveType): + column_type = _column_type.value + elif isinstance(_column_type, str): + column_type = _column_type + elif isinstance(_column_type, list): + column_type = [SchemaFieldGeneratorV2.build_column_type(_column_type[0])] + else: + column_type = { + "fields": [ + {"field": k, "type": SchemaFieldGeneratorV2.build_column_type(t)} for k, t in _column_type.items() + ] + } # type:ignore + + return column_type + + @classmethod + def build_relation(cls, collection: Collection, relation_name: str) -> SchemaV2Relation: + field_schema: RelationAlias = cast(RelationAlias, collection.get_field(relation_name)) + if is_many_to_many(field_schema): + return SchemaFieldGeneratorV2.build_many_to_many_schema(field_schema, relation_name) + elif is_many_to_one(field_schema): + return SchemaFieldGeneratorV2.build_many_to_one_schema(field_schema, relation_name) + elif is_one_to_many(field_schema): + return SchemaFieldGeneratorV2.build_one_to_many_schema(field_schema, relation_name) + elif is_one_to_one(field_schema): + return SchemaFieldGeneratorV2.build_one_to_one_schema(field_schema, relation_name) + else: + raise + + @classmethod + def build_one_to_one_schema(cls, relation: OneToOne, relation_name: str) -> SchemaV2Relation: + return { + "name": relation_name, + "type": "OneToOne", + "foreignCollection": relation["foreign_collection"], + "originKey": relation["origin_key"], + "originKeyTarget": relation["origin_key_target"], + } + + @classmethod + def build_many_to_one_schema(cls, relation: ManyToOne, relation_name: str) -> SchemaV2Relation: + return { + "name": relation_name, + "type": "ManyToOne", + "foreignCollection": relation["foreign_collection"], + "foreignKey": relation["foreign_key"], + "foreignKeyTarget": relation["foreign_key_target"], + } + + @classmethod + def build_one_to_many_schema(cls, relation: OneToMany, relation_name: str) -> SchemaV2Relation: + return { + "name": relation_name, + "type": "OneToMany", + "foreignCollection": relation["foreign_collection"], + "originKey": relation["origin_key"], + "originKeyTarget": relation["origin_key_target"], + } + + @classmethod + def build_many_to_many_schema(cls, relation: ManyToMany, relation_name: str) -> SchemaV2Relation: + return { + "name": relation_name, + "type": "ManyToMany", + "foreignCollection": relation["foreign_collection"], + "throughCollection": relation["through_collection"], + "originKey": relation["origin_key"], + "originKeyTarget": relation["origin_key_target"], + "foreignKey": relation["foreign_key"], + "foreignKeyTarget": relation["foreign_key_target"], + } diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/type_v2.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/type_v2.py new file mode 100644 index 000000000..86be32189 --- /dev/null +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/forest_schema/type_v2.py @@ -0,0 +1,214 @@ +from typing import Any, Dict, List, Literal, Optional + +from forestadmin.agent_toolkit.utils.forest_schema.type import ( + AgentStackMeta, + ForestServerSegment, + ServerValidationType, + WidgetEditConfiguration, +) +from forestadmin.datasource_toolkit.interfaces.actions import ActionFieldType +from forestadmin.datasource_toolkit.interfaces.fields import ColumnAlias +from typing_extensions import NotRequired, TypedDict + + +class SchemaV2Relation(TypedDict): + name: str + type: Literal["ManyToMany", "ManyToOne", "OneToOne", "OneToMany"] + foreignCollection: str + + throughCollection: NotRequired[str] + foreignKey: NotRequired[str] + foreignKeyTarget: NotRequired[str] + originKey: NotRequired[str] + originKeyTarget: NotRequired[str] + + +class SchemaV2Field(TypedDict): + name: str + type: ColumnAlias + isPrimaryKey: NotRequired[bool] + filterOperators: List[str] + enumerations: NotRequired[List[str]] + + isWritable: NotRequired[bool] + isSortable: NotRequired[bool] + + prefillFormValue: NotRequired[Optional[Any]] + validations: NotRequired[List[ServerValidationType]] + + +class SchemaV2ActionField(TypedDict): + name: str + type: ActionFieldType + description: NotRequired[Optional[str]] + + value: NotRequired[Optional[Any]] + prefillValue: NotRequired[Optional[Any]] + enumeration: NotRequired[Optional[List[str]]] + isReadOnly: NotRequired[bool] + isRequired: NotRequired[bool] + reference: NotRequired[Optional[str]] + widget: NotRequired[Optional[WidgetEditConfiguration]] + + +class SchemaV2Action(TypedDict): + id: str + name: str + scope: Literal["single", "bulk", "global"] + endpoint: str # should it include the 'prefix' setting of the agent ?? + fields: NotRequired[List[SchemaV2ActionField]] + download: NotRequired[bool] + isDynamicForm: NotRequired[bool] + + +class SchemaV2Collection(TypedDict): + name: str + fields: List[SchemaV2Field] + relations: List[SchemaV2Relation] + + segments: NotRequired[List[ForestServerSegment]] + actions: NotRequired[List[SchemaV2Action]] + + canList: NotRequired[bool] + canCreate: NotRequired[bool] + canUpdate: NotRequired[bool] + canDelete: NotRequired[bool] + + canCount: NotRequired[bool] + canChart: NotRequired[bool] + canSearch: NotRequired[bool] + canNativeQuery: NotRequired[bool] + + +class AgentMetaV2(TypedDict): + agent: str + agent_version: str + stack: AgentStackMeta + datasources: NotRequired[ + List[Dict[str, Any]] + ] # here to store "name", "version", "dialect", ... and other nice to have values without formal keys + + +class ForestSchemaV2(TypedDict): + collections: List[SchemaV2Collection] + meta: AgentMetaV2 + + +# MASKS +SCHEMA_V2_FIELDS_MASK = { + "enumerations": [], + "isPrimaryKey": False, + "prefillFormValue": None, + "isSortable": True, + "isWritable": True, + "validations": [], +} + +SCHEMA_V2_ACTION_FIELD_MASK = { + "value": None, + "prefillValue": None, + "enumeration": None, + "description": "", + "isReadOnly": False, + "isRequired": False, + "reference": None, + "widget": None, +} + +SCHEMA_V2_ACTION_MASK = { + "download": False, + "isDynamicForm": False, + "fields": [], +} + +SCHEMA_V2_COLLECTION_MASK = { + "segments": [], + "actions": [], + "fields": [], # I don't kow if we can have a collection without fields + "relations": [], # I don't kow if we can have a collection without relations + "canList": True, + "canCreate": True, + "canUpdate": True, + "canDelete": True, + "canCount": True, + "canSearch": True, + "canChart": True, + "canNativeQuery": True, +} + + +# reduce templates +def template_reduce_collection(collection: SchemaV2Collection) -> SchemaV2Collection: + fields: List[SchemaV2Field] = collection.get("fields", []) + relations: List[SchemaV2Relation] = collection.get("relations", []) + actions: List[SchemaV2Action] = collection.get("actions", []) + + reduced: SchemaV2Collection = {**collection} + reduced["fields"] = [template_reduce_field(field) for field in fields] + reduced["relations"] = relations + reduced["actions"] = [template_reduce_action(action) for action in actions] + return _reduce_from_template(reduced, SCHEMA_V2_COLLECTION_MASK) # type:ignore + + +def template_reduce_field(collection: SchemaV2Field) -> SchemaV2Field: + return _reduce_from_template(collection, SCHEMA_V2_FIELDS_MASK) # type:ignore + + +def template_reduce_action(action: SchemaV2Action) -> SchemaV2Action: + fields: List[SchemaV2ActionField] = action.get("fields", []) + reduced_action: SchemaV2Action = {**action} + reduced_action["fields"] = [template_reduce_action_field(action) for action in fields] + return _reduce_from_template(reduced_action, SCHEMA_V2_ACTION_MASK) # type:ignore + + +def template_reduce_action_field(action_field: SchemaV2ActionField) -> SchemaV2ActionField: + reduced: SchemaV2ActionField = _reduce_from_template(action_field, SCHEMA_V2_ACTION_FIELD_MASK) # type:ignore + return reduced + + +def _reduce_from_template(input, mask): + # reduced = {} + # for key, value in input.items(): + # if key not in mask or input[key] != mask[key]: + # reduced[key] = value + reduced = {**input} + for key, value in mask.items(): + if key in input and input[key] == value: + del reduced[key] + return reduced + + +# apply templates +def template_apply_collection(collection: SchemaV2Collection) -> SchemaV2Collection: + fields: List[SchemaV2Field] = collection.get("fields", []) + actions: List[SchemaV2Action] = collection.get("actions", []) + + full: SchemaV2Collection = {**collection} + full["fields"] = [template_apply_field(field) for field in fields] + full["actions"] = [template_apply_action(action) for action in actions] + return _apply_from_template(collection, SCHEMA_V2_COLLECTION_MASK) # type:ignore + + +def template_apply_field(collection: SchemaV2Field) -> SchemaV2Field: + return _apply_from_template(collection, SCHEMA_V2_FIELDS_MASK) # type:ignore + + +def template_apply_action(action: SchemaV2Action) -> SchemaV2Action: + fields = action.get("fields", []) + full: SchemaV2Action = {**action} + + full["fields"] = [template_apply_action_field(field) for field in fields] + return _apply_from_template(full, SCHEMA_V2_ACTION_MASK) # type:ignore + + +def template_apply_action_field(action_field: SchemaV2ActionField) -> SchemaV2ActionField: + return _apply_from_template(action_field, SCHEMA_V2_ACTION_FIELD_MASK) # type:ignore + + +def _apply_from_template(input, mask): + full = {} + for key, value in mask.items(): + full[key] = value + for key, value in input.items(): + full[key] = value + return full diff --git a/src/agent_toolkit/forestadmin/agent_toolkit/utils/http.py b/src/agent_toolkit/forestadmin/agent_toolkit/utils/http.py index 51a454f80..3b793ff2f 100644 --- a/src/agent_toolkit/forestadmin/agent_toolkit/utils/http.py +++ b/src/agent_toolkit/forestadmin/agent_toolkit/utils/http.py @@ -6,6 +6,7 @@ from forestadmin.agent_toolkit.exceptions import AgentToolkitException from forestadmin.agent_toolkit.forest_logger import ForestLogger from forestadmin.agent_toolkit.utils.forest_schema.type import ForestSchema +from forestadmin.agent_toolkit.utils.forest_schema.type_v2 import ForestSchemaV2 class ForestHttpApiException(AgentToolkitException): @@ -159,3 +160,21 @@ async def send_schema(cls, options: HttpOptions, schema: ForestSchema) -> bool: ) else: ForestLogger.log("info", "Schema was not updated since last run.") + + @classmethod + async def send_schema_v2(cls, options: HttpOptions, schema: ForestSchemaV2) -> bool: + ForestLogger.log("info", "Schema was updated, sending new version.") + ret = await cls.post( + cls.build_endpoint(options["server_url"], "/forest/v2/apimaps"), + schema, + {"forest-secret-key": options["env_secret"], "content-type": "application/json"}, + options["verify_ssl"], + ) + pass + # TODO: remove file writing just after this dump is only to compare schema during poc + if ret: + with open(options["schema_path"], "w") as fout: + json.dump(ret["schemaV1"], fout, indent=4) + + with open(f'{options["schema_path"].split(".json")[0]}_json_api.json', "w") as fout: + json.dump(ret["schemaV1JSONAPI"], fout, indent=4) diff --git a/src/datasource_django/forestadmin/datasource_django/collection.py b/src/datasource_django/forestadmin/datasource_django/collection.py index 8139b8cbc..60cf5eb07 100644 --- a/src/datasource_django/forestadmin/datasource_django/collection.py +++ b/src/datasource_django/forestadmin/datasource_django/collection.py @@ -19,6 +19,15 @@ class DjangoCollection(BaseDjangoCollection): + canList: bool = True + canCreate: bool = True + canUpdate: bool = True + canDelete: bool = True + canChart: bool = True + canCount: bool = True + canNativeQuery: bool = True + canSearch: bool = True + def __init__(self, datasource: Datasource, model: Model): super().__init__(model._meta.db_table, datasource) self._model = model diff --git a/src/datasource_django/forestadmin/datasource_django/datasource.py b/src/datasource_django/forestadmin/datasource_django/datasource.py index 88cd40e52..2c6d48672 100644 --- a/src/datasource_django/forestadmin/datasource_django/datasource.py +++ b/src/datasource_django/forestadmin/datasource_django/datasource.py @@ -1,13 +1,24 @@ +from importlib.metadata import version +from typing import Any, Dict + from django.apps import apps from forestadmin.datasource_django.collection import DjangoCollection from forestadmin.datasource_django.interface import BaseDjangoDatasource class DjangoDatasource(BaseDjangoDatasource): - def __init__(self) -> None: + def __init__(self): super().__init__() self._create_collections() + @classmethod + def mk_meta_entry(cls) -> Dict[str, Any]: + return { + "name": "DjangoDatasource", + "version": version("forestadmin-agent-django").replace("b", "-beta."), + "django_version": version("django").replace("b", "-beta."), + } + def _create_collections(self): models = apps.get_models(include_auto_created=True) for model in models: diff --git a/src/datasource_django/forestadmin/datasource_django/interface.py b/src/datasource_django/forestadmin/datasource_django/interface.py index 40684ddb0..7668463c8 100644 --- a/src/datasource_django/forestadmin/datasource_django/interface.py +++ b/src/datasource_django/forestadmin/datasource_django/interface.py @@ -6,7 +6,8 @@ class BaseDjangoCollection(Collection, abc.ABC): - def model(self) -> Model: + @property + def model(self) -> Model: # type: ignore """return model of the collection""" diff --git a/src/datasource_toolkit/forestadmin/datasource_toolkit/collections.py b/src/datasource_toolkit/forestadmin/datasource_toolkit/collections.py index 5457bca17..1d81be8c4 100644 --- a/src/datasource_toolkit/forestadmin/datasource_toolkit/collections.py +++ b/src/datasource_toolkit/forestadmin/datasource_toolkit/collections.py @@ -20,6 +20,16 @@ class CollectionException(DatasourceException): class Collection(CollectionInterface): + # collection capabilities + canList: bool + canCreate: bool + canUpdate: bool + canDelete: bool + canChart: bool + canCount: bool + canNativeQuery: bool + canSearch: bool + def __init__(self, name: str, datasource: Datasource[Self]): super().__init__() self._datasource = datasource @@ -29,8 +39,14 @@ def __init__(self, name: str, datasource: Datasource[Self]): "fields": {}, "searchable": False, "segments": [], - "countable": True, "charts": {}, + "chartable": self.canChart, + "listable": self.canList, + "creatable": self.canCreate, + "updatable": self.canUpdate, + "deletable": self.canDelete, + "countable": self.canCount, + "support_native_query": self.canCount, } def __repr__(self) -> str: @@ -72,7 +88,7 @@ def add_segments(self, segments: List[str]): self.schema["segments"].extend(segments) def enable_search(self): - self.schema["searchable"] = False + self.schema["searchable"] = True async def execute( self, diff --git a/src/datasource_toolkit/forestadmin/datasource_toolkit/datasources.py b/src/datasource_toolkit/forestadmin/datasource_toolkit/datasources.py index 9623aa5f3..b249791d7 100644 --- a/src/datasource_toolkit/forestadmin/datasource_toolkit/datasources.py +++ b/src/datasource_toolkit/forestadmin/datasource_toolkit/datasources.py @@ -1,4 +1,5 @@ -from typing import Dict, List +from importlib.metadata import version +from typing import Any, Dict, List from forestadmin.agent_toolkit.utils.context import User from forestadmin.datasource_toolkit.exceptions import DatasourceToolkitException @@ -15,6 +16,13 @@ class Datasource(DatasourceInterface[BoundCollection]): def __init__(self) -> None: self._collections: Dict[str, BoundCollection] = {} + @classmethod + def mk_meta_entry(cls) -> Dict[str, Any]: + return { + "name": "FromToolkitDatasource", + "version": version("forestadmin-datasource-toolkit").replace("b", "-beta."), + } + @property def schema(self): return {"charts": {}} diff --git a/src/datasource_toolkit/forestadmin/datasource_toolkit/interfaces/models/collections.py b/src/datasource_toolkit/forestadmin/datasource_toolkit/interfaces/models/collections.py index 5ce7550a5..ddd812673 100644 --- a/src/datasource_toolkit/forestadmin/datasource_toolkit/interfaces/models/collections.py +++ b/src/datasource_toolkit/forestadmin/datasource_toolkit/interfaces/models/collections.py @@ -1,5 +1,5 @@ import abc -from typing import Callable, Dict, Generic, List, TypedDict, TypeVar +from typing import Any, Callable, Dict, Generic, List, TypedDict, TypeVar from forestadmin.datasource_toolkit.interfaces.actions import Action from forestadmin.datasource_toolkit.interfaces.fields import FieldAlias @@ -9,22 +9,35 @@ class CollectionSchema(TypedDict): actions: Dict[str, Action] fields: Dict[str, FieldAlias] - searchable: bool segments: List[str] - countable: bool charts: Dict[str, Callable] + # collection capabilities + # it should be in the form of 'canSomething' but countable & searchable already exists + # because I'm lazy, I'm so sorry for 'chartable' 😅 + listable: bool + creatable: bool + updatable: bool + deletable: bool + chartable: bool + countable: bool + searchable: bool + support_native_query: bool + class Collection(abc.ABC): - @abc.abstractproperty + @property + @abc.abstractmethod def datasource(self) -> "Datasource[Self]": raise NotImplementedError - @abc.abstractproperty + @property + @abc.abstractmethod def name(self) -> str: raise NotImplementedError - @abc.abstractproperty + @property + @abc.abstractmethod def schema(self) -> CollectionSchema: raise NotImplementedError @@ -34,7 +47,13 @@ def schema(self) -> CollectionSchema: class Datasource(Generic[BoundCollection], abc.ABC): - @abc.abstractproperty + @classmethod + @abc.abstractmethod + def mk_meta_entry(cls) -> Dict[str, Any]: + raise NotImplementedError + + @property + @abc.abstractmethod def collections(self) -> List[BoundCollection]: raise NotImplementedError