def add_field(self, name: str, value: Field): if name in self.fields_map: raise ConfigurationError( "Field {} already present in meta".format(name)) setattr(self._model, name, value) value.model = self._model self.fields_map[name] = value self._fields = None if value.has_db_field: self.fields_db_projection[name] = value.source_field or name self._fields_db_projection_reverse = None if isinstance(value, fields.ManyToManyField): self.m2m_fields.add(name) self._fetch_fields = None elif isinstance(value, fields.BackwardFKRelation): self.backward_fk_fields.add(name) self._fetch_fields = None field_filters = get_filters_for_field(field_name=name, field=value, source_field=value.source_field or name) self._filters.update(field_filters) self.generate_filters()
def add_field(self, name: str, value: Field): if name in self.fields_map: raise ConfigurationError(f"Field {name} already present in meta") value.model = self._model self.fields_map[name] = value if value.has_db_field: self.fields_db_projection[name] = value.source_field or name if isinstance(value, fields.ManyToManyField): self.m2m_fields.add(name) elif isinstance(value, fields.BackwardFKRelation): self.backward_fk_fields.add(name) field_filters = get_filters_for_field( field_name=name, field=value, source_field=value.source_field or name ) self._filters.update(field_filters) self.finalise_fields()
def __new__(mcs, name: str, bases, attrs: dict, *args, **kwargs): fields_db_projection: Dict[str, str] = {} fields_map: Dict[str, fields.Field] = {} filters: Dict[str, Dict[str, dict]] = {} fk_fields: Set[str] = set() m2m_fields: Set[str] = set() o2o_fields: Set[str] = set() meta_class = attrs.get("Meta", type("Meta", (), {})) pk_attr: str = "id" # Searching for Field attributes in the class hierarchy def __search_for_field_attributes(base, attrs: dict): """ Searching for class attributes of type fields.Field in the given class. If an attribute of the class is an instance of fields.Field, then it will be added to the fields dict. But only, if the key is not already in the dict. So derived classes have a higher precedence. Multiple Inheritance is supported from left to right. After checking the given class, the function will look into the classes according to the MRO (method resolution order). The MRO is 'natural' order, in which python traverses methods and fields. For more information on the magic behind check out: `The Python 2.3 Method Resolution Order <https://www.python.org/download/releases/2.3/mro/>`_. """ for parent in base.__mro__[1:]: __search_for_field_attributes(parent, attrs) meta = getattr(base, "_meta", None) if meta: # For abstract classes for key, value in meta.fields_map.items(): attrs[key] = value else: # For mixin classes for key, value in base.__dict__.items(): if isinstance(value, fields.Field) and key not in attrs: attrs[key] = value # Start searching for fields in the base classes. inherited_attrs: dict = {} for base in bases: __search_for_field_attributes(base, inherited_attrs) if inherited_attrs: # Ensure that the inherited fields are before the defined ones. attrs = {**inherited_attrs, **attrs} if name != "Model": custom_pk_present = False for key, value in attrs.items(): if isinstance(value, fields.Field): if value.pk: if custom_pk_present: raise ConfigurationError( f"Can't create model {name} with two primary keys," " only single pk are supported") if value.generated and not isinstance( value, (fields.SmallIntField, fields.IntField, fields.BigIntField)): raise ConfigurationError( "Generated primary key allowed only for IntField and BigIntField" ) custom_pk_present = True pk_attr = key if not custom_pk_present and not getattr(meta_class, "abstract", None): if "id" not in attrs: attrs = {"id": fields.IntField(pk=True), **attrs} if not isinstance(attrs["id"], fields.Field) or not attrs["id"].pk: raise ConfigurationError( f"Can't create model {name} without explicit primary key if field 'id'" " already present") for key, value in attrs.items(): if isinstance(value, fields.Field): if getattr(meta_class, "abstract", None): value = deepcopy(value) fields_map[key] = value value.model_field_name = key if isinstance(value, fields.ForeignKeyField): fk_fields.add(key) elif isinstance(value, fields.OneToOneField): o2o_fields.add(key) elif isinstance(value, fields.ManyToManyFieldInstance): m2m_fields.add(key) else: fields_db_projection[key] = value.source_field or key filters.update( get_filters_for_field( field_name=key, field=fields_map[key], source_field=fields_db_projection[key], )) if value.pk: filters.update( get_filters_for_field( field_name="pk", field=fields_map[key], source_field=fields_db_projection[key], )) # Clean the class attributes for slot in fields_map: attrs.pop(slot, None) attrs["_meta"] = meta = MetaInfo(meta_class) meta.fields_map = fields_map meta.fields_db_projection = fields_db_projection meta._filters = filters meta.fk_fields = fk_fields meta.backward_fk_fields = set() meta.o2o_fields = o2o_fields meta.backward_o2o_fields = set() meta.m2m_fields = m2m_fields meta.default_connection = None meta.pk_attr = pk_attr meta._inited = False if not fields_map: meta.abstract = True new_class: "Model" = super().__new__(mcs, name, bases, attrs) # type: ignore for field in meta.fields_map.values(): field.model = new_class meta._model = new_class meta.finalise_fields() return new_class
def __new__(mcs, name: str, bases, attrs: dict, *args, **kwargs): fields_db_projection = {} # type: Dict[str,str] fields_map = {} # type: Dict[str, fields.Field] filters = {} # type: Dict[str, Dict[str, dict]] fk_fields = set() # type: Set[str] m2m_fields = set() # type: Set[str] if 'id' not in attrs: attrs['id'] = fields.IntField(pk=True) for key, value in attrs.items(): if isinstance(value, fields.Field): fields_map[key] = value value.model_field_name = key if isinstance(value, fields.ForeignKeyField): key_field = '{}_id'.format(key) value.source_field = key_field fields_db_projection[key_field] = key_field fields_map[key_field] = fields.IntField( reference=value, null=value.null, default=value.default, ) filters.update( get_filters_for_field( field_name=key_field, field=fields_map[key_field], source_field=key_field, )) fk_fields.add(key) elif isinstance(value, fields.ManyToManyField): m2m_fields.add(key) else: fields_db_projection[ key] = value.source_field if value.source_field else key filters.update( get_filters_for_field( field_name=key, field=fields_map[key], source_field=fields_db_projection[key])) attrs['_meta'] = meta = MetaInfo(attrs.get('Meta')) meta.fields_map = fields_map meta.fields_db_projection = fields_db_projection meta.fields_db_projection_reverse = { value: key for key, value in fields_db_projection.items() } meta.fields = set(fields_map.keys()) meta.db_fields = set(fields_db_projection.values()) meta._filters = filters meta.fk_fields = fk_fields meta.backward_fk_fields = set() meta.m2m_fields = m2m_fields meta.fetch_fields = fk_fields | m2m_fields meta.default_connection = None meta._inited = False if not fields_map: meta.abstract = True new_class = super().__new__(mcs, name, bases, attrs) return new_class
def __new__(mcs, name: str, bases, attrs: dict, *args, **kwargs): fields_db_projection = {} # type: Dict[str,str] fields_map = {} # type: Dict[str, fields.Field] filters = {} # type: Dict[str, Dict[str, dict]] fk_fields = set() # type: Set[str] m2m_fields = set() # type: Set[str] meta_class = attrs.get("Meta", type("Meta", (), {})) pk_attr = "id" if name != "Model": custom_pk_present = False for key, value in attrs.items(): if isinstance(value, fields.Field): if value.pk: if custom_pk_present: raise ConfigurationError( "Can't create model {} with two primary keys, " "only single pk are supported".format(name) ) elif value.generated and not isinstance( value, (fields.IntField, fields.BigIntField) ): raise ConfigurationError( "Generated primary key allowed only for IntField and BigIntField" ) custom_pk_present = True pk_attr = key if not custom_pk_present: if "id" not in attrs: attrs["id"] = fields.IntField(pk=True) if not isinstance(attrs["id"], fields.Field) or not attrs["id"].pk: raise ConfigurationError( "Can't create model {} without explicit primary key " "if field 'id' already present".format(name) ) for key, value in attrs.items(): if isinstance(value, fields.Field): if getattr(meta_class, "abstract", None): value = deepcopy(value) fields_map[key] = value value.model_field_name = key if isinstance(value, fields.ForeignKeyField): fk_fields.add(key) elif isinstance(value, fields.ManyToManyField): m2m_fields.add(key) else: fields_db_projection[key] = value.source_field or key filters.update( get_filters_for_field( field_name=key, field=fields_map[key], source_field=fields_db_projection[key], ) ) if value.pk: filters.update( get_filters_for_field( field_name="pk", field=fields_map[key], source_field=fields_db_projection[key], ) ) attrs["_meta"] = meta = MetaInfo(meta_class) meta.fields_map = fields_map meta.fields_db_projection = fields_db_projection meta._filters = filters meta.fk_fields = fk_fields meta.backward_fk_fields = set() meta.m2m_fields = m2m_fields meta.default_connection = None meta.pk_attr = pk_attr meta._inited = False if not fields_map: meta.abstract = True new_class = super().__new__(mcs, name, bases, attrs) # type: "Model" # type: ignore for field in meta.fields_map.values(): field.model = new_class meta._model = new_class return new_class