我有两个问题困扰着我。我面对的是一个实现,其中一些文档与不同级别的地理数据相关,并且希望工厂生成它们。让我们看一个我认为它可能起作用的例子:
from django.contrib.gis.db import models
class Country(models.Model):
name = models.CharField(max_length=60)
class Region(models.Model):
country = models.ForeignKey(Country, on_delete=models.PROTECT)
name = models.CharField(max_length=60)
class Law(models.Model):
text = models.CharField(max_length=60)
class Meta:
abstract = True
class CountryLaw(Law):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class RegionLaw(Law):
region = models.ForeignKey(Region, on_delete=models.CASCADE)
# Not sure this work but the idea is here
class LawManager(models.Manager):
def create_law(text,geodata):
if isinstance(geodata, Country):
return CountryLaw(text=text, country=geodata)
elif isinstance(geodata, Region)
return RegionLaw(text=text, region=geodata)
else:
raise TypeError("Inapropriate geodata type")
我想要一些工厂方法,因为我有一些工作来填充所有法律都通用的“法律”字段,但是这个例子没有显示它。 我的问题是:
我在google和stackoverflow上搜索答案,但不知道该用什么关键字,也没有找到任何可以帮助我的东西。。在
谢谢你的帮助!在
这里有几种选择。下面的“列表”并不是详尽无遗的,尽管它可能提供一些想法,并且可以基于这些想法构建变体。在
像现在这样离开模特
在这种情况下,我们将其建模为:
在这里我们构造了两个
Law
s,虽然我们当然可以超类这两个Law
,但这意味着每个都有自己的类型。在这样做的好处是,如果这两种语言有特定的语义,例如
CountryLaw
应该与RegionLaw
完全不同的处理,那么这就更容易实现。此外,如果CountryLaw
具有特定的字段,例如对于RegionLaw
s不重要(反之亦然),那么我们就避免在NULL
值(或其他占位符)上浪费磁盘空间。在缺点是,例如,如果我们想查询属于}所有地区的{}。如果您还有
'Germany'
的法律,我们必须分两个步骤进行查询:查询德国的CountryLaw
,以及查询{SubRegion
s、City
s等,这也很容易失控使用代理区域
这里我们认为所有的},我们使用一个代表整个国家的虚拟区域
Law
都是为一个特定的Region
而设计的诀窍是我们构造了一个Region
,它的行为就像整个国家一样。因此,除了'Saxony'
和{'Germany'
。在然后我们可以引入一个单独的
^{pr2}$Law
模型,它附属于Region
。如果我们经常需要区分一个地区和一个国家,我们可以添加一个字段is_country
,例如指定这是一个“国家代理”还是一个真正的地区:优点是我们只有一个
Law
对象,因此设计更容易。此外,查询映射到一个国家(包括或不包括地区)的法律也很容易。在缺点是,如果国家
Law
和地区Law
显著不同,那么这将导致大量的检查(每次检查附加的区域是否真的是一个区域,还是一个国家),而且还可能导致许多未使用的字段。此外,如果我们启用越来越多的层,我们需要引入越来越多的代理对象。例如,如果我们将使用三层(Country
,Region
,SubRegion
),那么我们需要为每个国家构造一个“代理”区域(它也包含一个代理子区域),并且对于每个区域,一个代理子区域。因此,如果存在n国家和m地区,这将导致2×n+m代理对象,这也会导致重复数据(我们会多次重复该国家/地区的名称,如果以后重命名某个国家或地区,则更新所有这些代理会带来一定的痛苦)。在使用类似于树的结构
如果级别的数量可能很大,或者是动态的(在某种意义上,有些“区域”有子区域,而对于其他区域则没有区域),或者我们希望以一种统一的方式处理所有这些级别,我们可以决定使用一种类似树的结构。在
在这里我们定义一个模型,例如
^{3}$Area
,一个Area
可以有一个parent
,这也是一个Area
,我们可以这样构造一个树结构。例如:然后我们可以给每个
Area
附加0,一个或多个定律。所以模型看起来像:这样做的好处是,我们有了一个适用于
Country
、Region
、Subregion
等的模型。此外,我们可以按照我们想要的方式实现一个层次结构,例如一些(小)国家没有Region
s(例如“城市国家”,如梵蒂冈城,新加坡,等等)。此外,Law
对象将链接到类似“区域”的对象。也很容易获得附属于某一领域的法律。然而,一个问题是,很难获得一个国家、其地区、其分区域等的所有信息。然而,这可以通过设计一个多对多表来处理,例如,设计一个多对多表,对这种树结构的传递闭包进行编码:这个多对多关系将包含一个国家与所有国家的链接它的地区、分区域等,但仍然不是很优雅。这也意味着所有这些
Area
实例都是统一表示的。因此,如果我们想在Area
中增加一份有正式语文的清单,所有地区都有“正式语文”,而大多数分区域可能只是“继承”其国家的官方语文。在在
Law
对象中使用GenericForeignKey
(Django特性)Django还有一种特殊的关系,称为^{} [doc]。对于这样的问题,这可能看起来是一个很好的特性,但我建议尽量避免这种关系。在
默认情况下,Django会为每个模型添加一个隐式主键:如果开发人员不使用},},等等
primary_key=True
指定一个字段。Django将自动添加一个IntegerField
,它将指定一个标识符作为主键。因此,可以合理地假设大多数模型都有一个IntegerField
作为主键(实际上,指定另一个主键是undjango)。我们还可以生成一个将每个模型映射到一个整数的列表:例如,0
映射到{1
映射到{这意味着大多数模型实例可以由两个整数标识:一个整数指定模型,另一个指定相应模型的主键。例如,}(假设我们使用上面段落中定义的“查找表”)。这是一个强大的概念:因此,我们可以使用两个数据库列来存储这些整数,并且每次都让Django获取对象。这就是
(0, 14)
是带有主键14
的{GenericForeignKey
背后的想法。因此,我们可以定义一个Law
,如:这意味着现在我们的
Law
存储了两个实字段:acontent_type
和object_id
,如果我们查询some_law.area
,Django将获取与这两个整数对应的对象。在因此,我们可以用它来指代
Country
,Region
,Subregion
,这在我们可以参考各种模型的情况下是有用的。但也有很多缺点。主要问题是,在我们希望在查询中使用这些关系的情况下,这些关系通常非常麻烦。实际上:假设我们想用area
字段加入我们的Law
模型。那我们该加入哪一张桌子?是Country
、Region
、SubRegion
?如果一个Law
指的是Country
,而另一个是指Region
,怎么办?所以通常我们不能JOIN
。在此外,模型本身并不保证
GenericForeignKey
总是指向一个类似“区域”的对象。它可以引用另一个Law
,aUser
,aCriminal
,等等。因此,您有责任编写一个合理的逻辑来确保这些关系是有意义的。虽然这看起来很容易,但很难保持良好的关系。由于没有FOREIGN KEY
约束,大多数数据库无法检查外键是否引用了一个有效的对象,因为“目标表”是未知的。在虽然有很多缺点,但在某些情况下,a
GenericForeignKey
可以是某些问题的优雅解决方案,但必须小心。在虽然-据我所知-没有公认的方法来在图表中指定这种关系,但它可以是这样的:
相关问题 更多 >
编程相关推荐