我目前正在开玩笑如何使用Django建模。基本情况是我有一个对象应该作为chassis
并提供一些sockets
。然后,在modules
的{{1}}上放置了大量不同的sockets
。我想在Django中将这些不同的chassis
建模为不同的类,但在数据库层使用公共类,可能涉及一些通用字段。
因此,数据库模型可能如下所示:
modules
当然,我不想用这种非规范化来破坏我的逻辑。这就是为什么我暗示某些应该使用Module表的class Module(models.model):
name = models.CharField(max_length=128)
# Or is there a better way to annotate a type?
type = models.CharField(max_length=128)
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
# Some kind of engine class that derives from Module
# but does nothing else then "mapping" the generic
# fields to something sensible
class Socket(models.Model):
is_on = models.ForeignKey(Chassis)
name = models.CharField(max_length=128)
type = models.CharField(max_length=128)
class Connection(models.Model):
chassis = models.ForeignKey(Chassis)
module = models.ForeignKey(Module)
via = models.ForeignKey(Socket)
class Chassis(models.Model):
name = models.CharField(max_length=128)
modules= models.ManyToManyField(Module, through='Connection')
class Group(models.Model):
name = models.CharField(max_length=128)
类,但提供“逻辑”getter和setter,有效地将数据映射为“Horsepower”到“int1”。
所以我的问题基本上是:
engine
字段? 答案 0 :(得分:1)
我对Django的合理性是什么?
一般的想法是可以的,但是非规范化可能会使您的查询不是最佳的。标准解决方案是为每种类型的模块创建子类Module
;这将创建一个module
表加上每个模块类型的表,其中包含特定于类型的内容。当然,这假设您不会在运行时创建或删除模块类型。
也就是说,您的模型存在一些问题:
class Module(models.model):
name = models.CharField(max_length=128)
# Or is there a better way to annotate a type?
type = models.CharField(max_length=128)
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
通常,type
会被规范化以节省空间:
class ModuleType(models.model):
name = models.CharField(max_length=128)
# Any other type-specific parameters.
class Module(models.model):
name = models.CharField(max_length=128)
type = models.ForeignKey(ModuleType, related_name="modules")
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
class Socket(models.Model):
is_on = models.ForeignKey(Chassis)
name = models.CharField(max_length=128)
type = models.CharField(max_length=128)
class Connection(models.Model):
chassis = models.ForeignKey(Chassis)
module = models.ForeignKey(Module)
via = models.ForeignKey(Socket)
class Chassis(models.Model):
name = models.CharField(max_length=128)
sockets = m
modules= models.ManyToManyField(Model, through='Socket')
Chassis
一团糟。你没有定义sockets
,写了Model
,你可能想要module
,而through
可能应该引用Connection
(through
模型必须在链接的两端都有ForeignKey
个。但是根据你的描述,我得到的更简单:
class Socket(models.Model):
chassis = models.ForeignKey(Chassis, related_name="sockets")
name = models.CharField(max_length=128)
# Is `type` a ModuleType? If so, use a ForeignKey.
# If not, create a SocketType model.
type = models.___
module = models.ForeignKey(Module, related_name="sockets")
class Chassis(models.Model):
name = models.CharField(max_length=128)
sockets = models.IntegerField()
modules = models.ManyToManyField(Socket)
通过更好地描述您的建模内容,可以进一步细化。例如,我不确定ManyToMany是你想要的。您可能需要从该机箱的实例拆分机箱的设计(即给定类型机箱的所有实例通用的东西,包括其套接字)(将参考设计,并有另一个表映射套接字到模块)。
是否可以自动构建正确的类型,具体取决于Module.type字段?
那是工厂设计模式。在Python中,您将其实现为构造函数的字典:
class Module(models.model):
# ...
CONSTRUCTORS = {}
@staticmethod
def register_constructor(type_name, constructor):
Module.CONSTRUCTORS[type_name] = constructor
def construct(self):
return Module.CONSTRUCTORS[self.type.name](self)
我认为您不需要特定的引擎类;各种模块类就足够了。
答案 1 :(得分:1)
为了定义抽象基类,您可以执行以下操作:
class Module(models.model):
name = models.CharField(max_length=128)
type = models.CharField(max_length=128)
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
class Meta:
abstract = True
class SpecificModule(Module):
subClassField = models.CharField(max_length=128)
我建议阅读文档的this part,因为它是处理继承和抽象类的一个非常好的起点。
您还可以定义不带class Meta: abstract = True
的父模块类。唯一的区别是abstract = True
类SpecificModule
的所有字段和抽象模块父类的所有字段都将在子类表中为特定模块创建,而没有{{1}定义类的表将创建模块,包含Module表中可用的所有“通用”字段,以及表中特定于模块类的所有子类特定字段。
编辑:回答有关父母与子女之间关系的问题。
由于在子类表(docs)中创建了隐式的一对一字段,您可以使用此查询获取子对象。
abstract = True
我认为Django也应该创建一个默认的related_name,但不确定它是哪一个。
请注意,仅在#get the parent
parent = Module.objects.get(name="my first module")
#this is possible
print parent.name
>>> "my first module"
#this is not possible
print parent.subClassField
>>> Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Module' object has no attribute 'subClassField'
#get the corresponding child
child = SpecificModule.objects.get(module_ptr_id=parent.pk)
#finally we can print the value
print child.subClassField
情况下创建从父级到子级的隐式一对一关系。然而,如果abstract=False
您不会将抽象父作为对象,那么它是抽象的..