django的实体关系管理
django-entit的Python项目详细描述
django实体是一个应用程序,它为django项目提供了在单独的、包含良好且易于访问的表中镜像其实体和实体关系的能力。只支持PostgreSQL。
Django Entity为大型项目提供了更好地隔离其应用程序的能力,同时将那些必须在主项目中处理实体及其关系的应用程序中特定于应用程序的代码最小化。
什么是实体?实体是django项目中的任何模型。例如,实体可以是django用户模型或用户组。类似地,实体关系定义不同类型实体之间的超级和子关系。例如,组将是用户的超级实体。Django Entity应用程序允许您在模型定义中轻松表达这种关系,并将其同步到项目中任何其他应用程序都可以访问的集中位置。
用例
假设您有一个django项目,它定义了许多类型的用户分组。例如,假设在您的企业项目中,您允许用户定义其经理、公司职位和区域分支位置。类似地,假设您有一个应用程序,它可以根据用户的经理(或该经理手下的任何人)、他们的职位或所在地区向用户组发送电子邮件。这个电子邮件应用程序可能需要知道这些关系的特定于应用程序的建模才能构建。类似地,根据模型的不同,查询manager层次结构下的所有用户可能是一个代价高昂的查找。
使用django实体,可以编写电子邮件应用程序来采用实体模型,而不必理解每个组的复杂关系。传递给电子邮件应用程序的实体模型可以是CompanyPosition模型,get_sub_entities()。is_any_type(contentType.objects.get_for_model(user))将返回该CompanyPosition模型下的所有用户模型。这使得电子邮件应用程序可以完全与主项目定义其关系的方式隔离开来。类似地,在companyposition下获取所有用户模型的查询可能比直接从项目中查询要高效得多(取决于项目的模型结构)。
入门-配置实体同步
基本用例
与django的model admin类似,通过在实体注册表中注册实体来配置实体,如下所示:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()
就像这样,帐户
模型现在在每次保存、删除或更新帐户的任何M2M字段时都会同步到实体
表。
更高级的同步选项
如果django实体只将对象同步到单个实体
表,那么django实体不会太多。为了利用镜像关系的强大功能,用户必须为继承entityconfig
的实体定义配置。下面是一个小例子,它将我们的帐户模型扩展为有一个组
外键。
fromentity.configimportregister_entity,EntityConfigclassAccount(Model):email=models.CharField(max_length=64)group=models.ForeignKey(Group)@register_entity()classGroupConfig(EntityConfig):queryset=Group.objects.all()@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_super_entities(self,model_objs):return{Group:[(model_obj.id,model_obj.group_id)formodel_objinmodel_objs]}
在上面的场景中,我们使用默认的实体配置镜像组
模型。但是,帐户
模型现在使用继承实体配置
的特殊配置。它覆盖get_super_entities
函数,将作为超级实体的所有模型对象的列表返回给帐户。帐户同步后,用户可以对帐户关系进行各种筛选分组(稍后详细介绍)。
注意-在上面的示例中,我们还使用了register\u entity
装饰符,这实际上是执行entity\u registry.register\u entity(model\u class,entity\u config\u class)
除了能够镜像关系之外,还可以扩展实体配置以镜像有关实体的元数据。例如,在前面的示例中使用帐户
模型:
@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_super_entities(self,model_objs):return{Group:[(model_obj.id,model_obj.group_id)formodel_objinmodel_objs]}defget_entity_meta(self,model_obj):return{'email':model_obj.email}
通过上述配置,每个帐户实体都将有一个entity_meta字段(一个json字段),该字段还镜像了email属性。元数据镜像功能强大,可以在需要访问具体模型的具体字段的实体上构建通用应用程序(无需预取实体指向的所有具体模型)。
除了元数据之外,实体还具有镜像显示名称
字段的能力,以便为也可以在数据库中筛选的实体提供人类可读的名称。默认情况下,显示名称
字段使用应用于具体模型实例的unicode()
函数的结果。用户可以通过重写实体配置中的get\u display\u name
方法来重写此行为。
实体也可以配置为活动或非活动,这可以通过在配置中添加get\u is\u active
函数来完成,如果实体是活动的,则返回true
(默认值),否则返回false
。
高级同步(续)-实体类型
实体可以用它们的"种类"来标记高级过滤功能。实体类型允许用户显式地声明要镜像的实体类型,同时提供关于实体类型的可读内容。这是通过镜像每个实体
指向的
实体kind
对象中的一个唯一的名称
字段和一个显示名称
字段来实现的。
默认情况下,django实体将实体的内容类型镜像为其类型。名称字段将是内容类型的app_标签
,后跟内容类型的模型
。对于该名称对实体类型的描述不够充分的情况,用户可以覆盖实体配置中的get\u entity\u kind
函数。例如:
@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_entity_kind(self,model_obj):return(model_obj.email_domain,'Email domain {0}'.format(model_obj.email_domain))
在上述情况下,根据电子邮件的域将帐户实体分为不同的类型。返回元组的第二个值提供了一个人类可读的正在创建的类型版本。
更高级的同步-观看其他型号
在hood下面,django实体在镜像模型上进行保存、删除和m2m更新时同步镜像实体表。但是,有些模型实际上可能依赖于模型的直接字段没有指向的对象。例如,假设我们有以下型号:
classGroup(models.Model):group_name=models.CharField()classUser(models.Model):email=models.CharField()groups=models.ManyToManyField(Group)classAccount(models.Model):user=models.OneToOneField(User)
现在,假设帐户
模型希望将用户
模型中的每个组
模型添加为其超级实体。这将通过以下配置设置:
@register_entity()classGroupConfig(EntityConfig):queryset=Group.objects.all()@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_super_entities(self,model_objs):return{Group:[(model_obj.id,group.id)formodel_objinmodel_objsforgroupinmodel_obj.user.groups.all()]}
尽管这是很好的,如果这是现成的,django实体无法知道帐户
模型需要在其关联的用户
模型中的字段更改时更新。为了确保帐户
模型正确镜像,请在实体配置中添加一个监视
类变量,如下所示:
@register_entity()classGroupConfig(EntityConfig):queryset=Group.objects.all()@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()watching=[(User,lambdauser_obj:Account.objects.filter(user=user_obj)),]defget_super_entities(self,model_objs):return{Group:[(model_obj.id,group.id)formodel_objinmodel_objsforgroupinmodel_obj.user.groups.all()]}
监视字段定义元组列表。每个元组中的第一个元素表示要监视的模型。元组中的第二个元素描述用于访问与更改的监视模型相关的实体模型的函数。
这是另一个早晨e使用指向帐户的地址
模型的复杂示例。
classAddress(models.Model):account=models.ForeignKey(Account)
要在帐户
模型的
用户
模型更改时使地址模型同步,请定义如下实体配置:
@register_entity()classAddressConfig(EntityConfig):queryset=Address.objects.all()watching=[(User,lambdauser_model_obj:Address.objects.filter(account__user=user_model_obj)),]
同样,在引擎盖下发生的所有事情是,当一个用户
模型被更改时,与该更改的用户模型相关的所有实体模型都被返回,以便它们可以被同步。
确保实体同步最佳查询
由于用户可能需要从许多不同的外键中镜像许多不同的超级实体,因此向django实体提供缓存提示是有益的。这可以通过简单地将预取的django queryset提供给实体配置中的queryset
属性来实现。例如,我们以前的帐户实体配置需要执行以下操作:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()0
当虚拟实体或所有实体同步时,queryset将用于访问帐户
模型,并传递给实体配置的相关方法。
同步实体
模型在配置并注册到django实体时将自动同步。但是,在配置实体之后,用户需要首先同步所有实体(然后在发生配置更改时重新同步所有实体)。这可以通过sync_entities management命令来完成:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()1
类似地,您可以直接调用函数来同步芹菜处理作业或您自己的应用程序代码中的实体。
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()2
请注意,如果用户希望同步单个实体,sync_entities()
函数将获取模型对象的可变长度列表:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()3
根据镜像的关系数量,实体同步可能代价高昂。如果用户要更新一行中镜像为实体的许多模型,建议关闭同步,显式同步所有更新的实体,然后重新启用同步。这可以按如下方式完成:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()4
访问实体
同步实体后,可以在主实体表中访问它们。实体
模型具有以下字段:
实体类型
:镜像实体的内容类型
。实体ID
:镜像实体的对象ID。实体元数据
:关于实体的镜像元数据的jsonfield(或null或无镜像)。实体种类
:描述镜像实体类型的实体种类模型。默认为与实体内容类型相关的参数。是否处于活动状态
:如果实体处于活动状态,则为true,否则为false。
除了这些基本字段之外,以下所有函数都可以直接在实体
模型或实体
模型管理器上调用。
基本模型和管理器功能
注意,由于实体是可激活的(即可以有活动和非活动状态),实体模型管理器默认情况下只访问活动实体。如果用户希望访问每个实体(活动或非活动),则必须通过all_objects
管理器,该管理器在下面的示例代码中使用。下面的方法可用于对象
和所有对象
模型管理器,尽管活动的
和非活动的
方法在对象
模型管理器上没有用,因为它已经过滤了活动实体。
获取对象(模型对象)
get_for_obj函数接受一个模型对象并返回相应的实体。仅在实体
模型管理器中可用。
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()5
活动()
返回活动实体。仅适用于使用所有对象
模型管理器时。请注意,
对象
已经只过滤活动实体。
不活动()
与active()相反。仅适用于使用
所有对象
模型管理器时。请注意,
对象
已忽略不活动的实体。
是任何种类(实体种类)
返回提供的任何实体类型的所有实体。
不是任何种类(实体种类)
与相反的是任何种类的
是所有的子实体(超级实体)
返回属于每个提供的超级实体的子实体的实体(如果没有提供超级实体,则返回全部)。
例如,如果希望按属于组A和组B的实体筛选所有帐户实体,则代码将如下所示:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()6
是否有任何子实体(超级实体)
返回任何一个提供的超级实体的子实体(如果没有提供超级实体,则返回所有子实体)。
是所有种类的子种类(超级实体种类)
返回所提供种类集包含在其所有超级实体种类集中的实体
是任何种类的子种类(超级实体种类)
返回在所提供的种类集中至少包含一个超级实体种类的实体(如果未提供种类,则返回全部)
缓存关系()
cache_relationships函数对于预取关系信息非常有用。如果对实体关系执行筛选,则在没有缓存关系功能的情况下访问实体将导致许多额外的数据库查询。
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()7
如果要忽略缓存子实体或超级实体关系,只需将cache_sub=false
或cache_super=false
作为关键字参数传递给函数。请注意,默认情况下这两个标志都已打开。
链接过滤功能
列出的所有管理器功能都可以链接,因此可以进行以下组合:
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()8
任意实体组
一旦实体及其关系同步设置完成,大多数实体分组将自动编码为超级/子实体关系。但是,在某些情况下,自动编码的组无法捕获有用的组的全部范围。
为了在不需要额外同步代码的情况下支持任意实体组,提供了entitygroup
模型。该模型提供了向组中添加和删除实体的方便功能,以及查询任意组中的实体的方法。
除了将单个实体添加到EntityGroup之外,还可以非常容易地将具有给定类型的实体的所有子实体添加到EntityGroup
中。执行以下操作:
- 创建
实体组
- 将单个实体添加到组中
- 将给定类型的所有子实体添加到组中
- 查询组中的所有实体
fromentity.configimportEntityConfig,register_entityclassAccount(Model):email=models.CharField(max_length=64)@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()9
运行上述代码后,组中的所有实体都将是
包含实体的实体的查询集
作为的所有子实体,某个超级实体的实体类型是
某种实体
以下方法在entitygroup
s
所有实体
获取组中所有单个实体的列表。这会拉出来的 所有已添加的实体,组合所有 分别添加和添加的所有实体 因为它们是添加了 组,具有指定的实体类型。
添加实体
添加单个实体或所有子实体(具有给定类型) 一个超级实体。有两种方法可以将实体添加到 使用此方法的组。第一个将单个实体添加到 组。第二个加上所有的人R实体 集团的特定子实体。
这样既可以利用现有分组,也可以允许其他分组
任意添加。个人和子实体组成员资格
可以添加到单个实体组
添加单个实体的语法与指定 要添加的实体:
fromentity.configimportregister_entity,EntityConfigclassAccount(Model):email=models.CharField(max_length=64)group=models.ForeignKey(Group)@register_entity()classGroupConfig(EntityConfig):queryset=Group.objects.all()@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_super_entities(self,model_objs):return{Group:[(model_obj.id,model_obj.group_id)formodel_objinmodel_objs]}0
添加子实体组就像指定 超级实体和子实体类型:
fromentity.configimportregister_entity,EntityConfigclassAccount(Model):email=models.CharField(max_length=64)group=models.ForeignKey(Group)@register_entity()classGroupConfig(EntityConfig):queryset=Group.objects.all()@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_super_entities(self,model_objs):return{Group:[(model_obj.id,model_obj.group_id)formodel_objinmodel_objs]}1
批量添加实体
将多个实体或子实体组添加到
实体组
。它需要一个元组列表,其中
tuple是一个实体
实例,第二个是
实体类型
实例或无
fromentity.configimportregister_entity,EntityConfigclassAccount(Model):email=models.CharField(max_length=64)group=models.ForeignKey(Group)@register_entity()classGroupConfig(EntityConfig):queryset=Group.objects.all()@register_entity()classAccountConfig(EntityConfig):queryset=Account.objects.all()defget_super_entities(self,model_objs):return{Group:[(model_obj.id,model_obj.group_id)formodel_objinmodel_objs]}2
删除实体
从
实体组
。此方法使用与add_entity
相同的语法。
批量删除实体
从
实体组
。此方法使用与
批量添加实体
批量覆盖
此方法用一组新的组替换所有组成员
成员。它的语法与bulk\u add\u实体的语法相同
许可证
MIT许可证(有关详细信息,请参阅许可证文件)。