def _init_relations(cls): for app_name, app in cls.apps.items(): for model_name, model in app.items(): if model._meta._inited: continue else: model._meta._inited = True if not model._meta.table: model._meta.table = model.__name__.lower() for field in model._meta.fk_fields: field_object = model._meta.fields_map[field] reference = field_object.model_name related_app_name, related_model_name = reference.split('.') related_model = cls.apps[related_app_name][ related_model_name] field_object.type = related_model backward_relation_name = field_object.related_name if not backward_relation_name: backward_relation_name = '{}s'.format( model._meta.table) if backward_relation_name in related_model._meta.fields: raise ConfigurationError( 'backward relation "{}" duplicates in model {}'. format(backward_relation_name, related_model_name)) fk_relation = fields.BackwardFKRelation( model, '{}_id'.format(field)) setattr(related_model, backward_relation_name, fk_relation) related_model._meta.filters.update( get_backward_fk_filters(backward_relation_name, fk_relation)) related_model._meta.backward_fk_fields.add( backward_relation_name) related_model._meta.fetch_fields.add( backward_relation_name) related_model._meta.fields_map[ backward_relation_name] = fk_relation related_model._meta.fields.add(backward_relation_name) for field in model._meta.m2m_fields: field_object = model._meta.fields_map[field] if field_object._generated: continue backward_key = field_object.backward_key if not backward_key: backward_key = '{}_id'.format(model._meta.table) field_object.backward_key = backward_key reference = field_object.model_name related_app_name, related_model_name = reference.split('.') related_model = cls.apps[related_app_name][ related_model_name] field_object.type = related_model backward_relation_name = field_object.related_name if not backward_relation_name: backward_relation_name = '{}s'.format( model._meta.table) if backward_relation_name in related_model._meta.fields: raise ConfigurationError( 'backward relation "{}" duplicates in model {}'. format(backward_relation_name, related_model_name)) if not field_object.through: related_model_table_name = ( related_model._meta.table if related_model._meta.table else related_model.__name__.lower()) field_object.through = '{}_{}'.format( model._meta.table, related_model_table_name, ) m2m_relation = fields.ManyToManyField( '{}.{}'.format(app_name, model_name), field_object.through, forward_key=field_object.backward_key, backward_key=field_object.forward_key, related_name=field, type=model) m2m_relation._generated = True setattr( related_model, backward_relation_name, m2m_relation, ) model._meta.filters.update( get_m2m_filters(field, field_object)) related_model._meta.filters.update( get_m2m_filters(backward_relation_name, m2m_relation)) related_model._meta.m2m_fields.add(backward_relation_name) related_model._meta.fetch_fields.add( backward_relation_name) related_model._meta.fields_map[ backward_relation_name] = m2m_relation related_model._meta.fields.add(backward_relation_name)
def _init_relations(cls) -> None: def get_related_model(related_app_name: str, related_model_name: str): """ Test, if app and model really exist. Throws a ConfigurationError with a hopefully helpful message. If successfull, returns the requested model. """ try: return cls.apps[related_app_name][related_model_name] except KeyError: if related_app_name not in cls.apps: raise ConfigurationError( "No app with name '{}' registered.".format( related_app_name)) raise ConfigurationError( "No model with name '{}' registered in app '{}'.".format( related_model_name, related_app_name)) def split_reference(reference: str) -> Tuple[str, str]: """ Test, if reference follow the official naming conventions. Throws a ConfigurationError with a hopefully helpful message. If successfull, returns the app and the model name. """ items = reference.split(".") if len(items) != 2: # pragma: nocoverage raise ConfigurationError( ("'%s' is not a valid model reference Bad Reference." " Should be something like <appname>.<modelname>.") % reference) return (items[0], items[1]) for app_name, app in cls.apps.items(): for model_name, model in app.items(): if model._meta._inited: continue model._meta._inited = True if not model._meta.table: model._meta.table = model.__name__.lower() for field in model._meta.fk_fields: fk_object = cast(fields.ForeignKeyField, model._meta.fields_map[field]) reference = fk_object.model_name related_app_name, related_model_name = split_reference( reference) related_model = get_related_model(related_app_name, related_model_name) key_field = "{}_id".format(field) key_fk_object = deepcopy(related_model._meta.pk) key_fk_object.pk = False key_fk_object.index = fk_object.index key_fk_object.default = fk_object.default key_fk_object.null = fk_object.null key_fk_object.generated = fk_object.generated key_fk_object.reference = fk_object key_fk_object.description = fk_object.description if fk_object.source_field: key_fk_object.source_field = fk_object.source_field fk_object.source_field = key_field else: fk_object.source_field = key_field key_fk_object.source_field = key_field model._meta.add_field(key_field, key_fk_object) fk_object.type = related_model backward_relation_name = fk_object.related_name if not backward_relation_name: backward_relation_name = "{}s".format( model._meta.table) if backward_relation_name in related_model._meta.fields: raise ConfigurationError( 'backward relation "{}" duplicates in model {}'. format(backward_relation_name, related_model_name)) fk_relation = fields.BackwardFKRelation( model, "{}_id".format(field), fk_object.null, fk_object.description) related_model._meta.add_field(backward_relation_name, fk_relation) for field in list(model._meta.m2m_fields): m2m_object = cast(fields.ManyToManyField, model._meta.fields_map[field]) if m2m_object._generated: continue backward_key = m2m_object.backward_key if not backward_key: backward_key = "{}_id".format(model._meta.table) if backward_key == m2m_object.forward_key: backward_key = "{}_rel_id".format( model._meta.table) m2m_object.backward_key = backward_key reference = m2m_object.model_name related_app_name, related_model_name = split_reference( reference) related_model = get_related_model(related_app_name, related_model_name) m2m_object.type = related_model backward_relation_name = m2m_object.related_name if not backward_relation_name: backward_relation_name = m2m_object.related_name = "{}_through".format( model._meta.table) if backward_relation_name in related_model._meta.fields: raise ConfigurationError( 'backward relation "{}" duplicates in model {}'. format(backward_relation_name, related_model_name)) if not m2m_object.through: related_model_table_name = ( related_model._meta.table if related_model._meta.table else related_model.__name__.lower()) m2m_object.through = "{}_{}".format( model._meta.table, related_model_table_name) m2m_relation = fields.ManyToManyField( "{}.{}".format(app_name, model_name), m2m_object.through, forward_key=m2m_object.backward_key, backward_key=m2m_object.forward_key, related_name=field, type=model, description=m2m_object.description, ) m2m_relation._generated = True model._meta.filters.update( get_m2m_filters(field, m2m_object)) related_model._meta.add_field(backward_relation_name, m2m_relation)
def _init_relations(cls) -> None: for app_name, app in cls.apps.items(): for model_name, model in app.items(): if model._meta._inited: continue else: model._meta._inited = True if not model._meta.table: model._meta.table = model.__name__.lower() for field in model._meta.fk_fields: fk_object = cast(fields.ForeignKeyField, model._meta.fields_map[field]) reference = fk_object.model_name related_app_name, related_model_name = reference.split(".") related_model = cls.apps[related_app_name][ related_model_name] key_field = "{}_id".format(field) fk_object.source_field = key_field key_fk_object = deepcopy(related_model._meta.pk) key_fk_object.pk = False key_fk_object.index = fk_object.index key_fk_object.default = fk_object.default key_fk_object.null = fk_object.null key_fk_object.generated = fk_object.generated key_fk_object.reference = fk_object model._meta.add_field(key_field, key_fk_object) fk_object.type = related_model backward_relation_name = fk_object.related_name if not backward_relation_name: backward_relation_name = "{}s".format( model._meta.table) if backward_relation_name in related_model._meta.fields: raise ConfigurationError( 'backward relation "{}" duplicates in model {}'. format(backward_relation_name, related_model_name)) fk_relation = fields.BackwardFKRelation( model, "{}_id".format(field)) related_model._meta.add_field(backward_relation_name, fk_relation) for field in model._meta.m2m_fields: m2m_object = cast(fields.ManyToManyField, model._meta.fields_map[field]) if m2m_object._generated: continue backward_key = m2m_object.backward_key if not backward_key: backward_key = "{}_id".format(model._meta.table) m2m_object.backward_key = backward_key reference = m2m_object.model_name related_app_name, related_model_name = reference.split(".") related_model = cls.apps[related_app_name][ related_model_name] m2m_object.type = related_model backward_relation_name = m2m_object.related_name if not backward_relation_name: backward_relation_name = m2m_object.related_name = "{}_through".format( model._meta.table) if backward_relation_name in related_model._meta.fields: raise ConfigurationError( 'backward relation "{}" duplicates in model {}'. format(backward_relation_name, related_model_name)) if not m2m_object.through: related_model_table_name = ( related_model._meta.table if related_model._meta.table else related_model.__name__.lower()) m2m_object.through = "{}_{}".format( model._meta.table, related_model_table_name) m2m_relation = fields.ManyToManyField( "{}.{}".format(app_name, model_name), m2m_object.through, forward_key=m2m_object.backward_key, backward_key=m2m_object.forward_key, related_name=field, type=model, ) m2m_relation._generated = True model._meta.filters.update( get_m2m_filters(field, m2m_object)) related_model._meta.add_field(backward_relation_name, m2m_relation)