Django - 设计模型关系 - 管理界面和内联

时间:2009-12-16 23:55:30

标签: database django database-design

我认为我对Django的FK和管理员的理解有点不对,所以我重视如何建模以下案例的任何输入。

首先,我们有通用的Address对象。然后,我们有User,每个都有UserProfile。通过这个,用户属于部门,也有地址。

部门本身也可以有多个地址,也可以是部门主管。所以它可能是这样的(这是我现在正在讨厌的事情):

class Address(models.Model):
    street_address = models.CharField(max_length=20)
    etc...

class Department(models.Model):
    name = models.CharField(max_lenght=20)
    head_of_department = models.OneToOneField(User)
    address = models.ForeignKey(Address)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    address = models.ForeignKey(Address)
    department = models.OneToOneField(Department)

无论如何,首先,这是建立关系的正确方法吗?

其次,我希望它出现在管理员中,你可以编辑一个部门,在那个页面上,它有一个内联列表,列出了所有要编辑的地址。我已经尝试设置一个AddressInline类,并将其作为内联附加到Department。

class AddressInline(admin.TabularInline):
    model = Address

class DepartmentAdmin(admin.ModelAdmin):
    inlines = [AddressInline]

但是,当我尝试显示时,我得到:

Exception at /admin/people/department/1/
<class 'people.models.Address'> has no ForeignKey to <class 'people.models.Department'>

干杯, 维克多

2 个答案:

答案 0 :(得分:2)

由于您似乎希望UserProfile或Department具有可能的许多地址,因此您的ForeignKeys是向后的。单个ForeignKey只能指向一个模型实例,而可以指向单个模型实例的ForeignKeys数量没有限制。因此,您的ForeignKey应该在地址上(在这种情况下,您的内联将按原样运行)。

复杂因素是你有一个地址模型,你想将它与其他两个模型联系起来;地址上的单个ForeignKey不能同时指向UserProfile和Department。一种解决方案是具有两个地址模型(DepartmentAddress,具有到Department的ForeignKey,以及UserAddress,具有到UserProfile的ForeignKey)。您可以通过从包含所有数据字段的abstract base class继承这些重复来减少代码中的重复,但最终仍会在数据库中使用两个大致相同的表。

另一个选项是在地址上有一个GenericForeignKey,它可以指向任何模型的实例。您的内联将需要成为GenericInlineModelAdmin。这违反了纯数据库规范化,并且不允许数据库进行正确的完整性检查。如果你将来有更多的模型也有地址,我会考虑这个;如果它可能仅限于当前的两个,我可能会选择上面的选项。

答案 1 :(得分:0)

我从你的模特中读到你的模特你想要的东西:

A department has one to many addresses

A department has one and only one user (as head of department)

A user (through his profile) belongs to one to many departments

A user (through his profile) has one to many addresses

如果这是你的意图,意味着没有用户不会有地址或部门的情况,也不会有部门没有地址或部门主管的情况;然后我会说你的模型是好的应该是:

class Department(models.Model):
    name = models.CharField(max_lenght=20)
    head_of_department = models.OneToOneField(User)
    address = models.ForeignKey(Address)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    address = models.ForeignKey(Address)
    department = models.OneToOneField(Department)

class Address(models.Model):
    street_address = models.CharField(max_length=20)
    ...

    class Meta:
        abstract = True

class UserAddress(Address):
    user_profile = models.ForeignKey(UserProfile)

class DepartmentAddress(Address):
    department = models.ForeignKey(Department)

详细了解abstract classes

您的模型未考虑的是两个用户具有相同地址的可能性,和/或两个部门将具有相同地址的可能性。由于您没有在地址上指定唯一约束(我可以看到),我认为您可以在地址表中多次显示实际地址。

如果你没事;细

您收到的错误消息说明了一个事实:地址部门没有外键。 您必须恢复该内联的关系才能工作。这意味着,在编辑地址时,您可以编辑与之关联的任何部门;但不是相反的。根据我上面建议的模型,你不应该看到这个错误。

请参阅example from the docs。注意Author has many Books如何以及关系的多方面如何是内联的。