【问题标题】:Django - Designing Model Relationships - Admin interface and InlineDjango - 设计模型关系 - 管理界面和内联
【发布时间】:2010-12-27 11:30:57
【问题描述】:

我认为我对 Django 的 FK 和 admin 的理解有点错误,所以我会重视有关如何为以下案例建模的任何意见。

首先,我们有通用的 Address 对象。然后,我们有用户,每个人都有一个 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'>

干杯, 维克多

【问题讨论】:

  • 您需要使用ManyToManyField 作为 Department 和 UserProfile 类的地址。
  • Celopes:感谢您指出这一点,已经回去接受旧的了。我没有意识到我必须同时投票和接受......哈哈。

标签: database django database-design


【解决方案1】:

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

复杂的因素是您只有一个地址模型,并且您希望将其与其他两个模型相关联; Address 上的单个 ForeignKey 不能同时指向 UserProfile 和 Department。一种解决方案是有两个地址模型(DepartmentAddress,带有一个 ForeignKey 到 Department,和 UserAddress,带有一个 ForeignKey 到 UserProfile)。您可以通过让它们都继承自包含所有数据字段的 abstract base class 来减少代码中的重复,但您最终仍会在数据库中得到两个大部分相同的表。

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

【讨论】:

  • 嘿,苦力,谢谢。所以你说 FK 字段应该在地址上,而不是 UserProfile/Department 上。必须尝试解决这个问题 - 如果它们是 SQL 表,那是在 DB 理论中通常会采用的方式吗?您将如何使用 SQL 理论中的通用地址表来处理这种特殊情况?我想我可能会尝试抽象基类方法,似乎比 GenericRelations 工作少......哈哈。然后它可以很好地与管理界面一起工作,对吧,因为这两个 Address 子类本质上是不同的对象?干杯,维克多
  • Victor:是的,在直接的 SQL 中,您仍然会将外键字段放在多对一关系的“一”侧。是的,抽象基类解决方案将与管理内联很好地配合使用(两者都可以,真的)。
【解决方案2】:

我读了你的模型你想从你的模型中得到什么:

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

如果这是您的意图,这意味着用户不会没有地址或部门,也不会出现部门没有地址或部门负责人的情况;那么我会说你的模型 are OK 应该是:

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的信息。

您的模型没有考虑两个用户具有相同地址和/或两个部门具有相同地址的可能性。由于您没有指定地址的唯一约束(我可以看到),因此我假设您可以接受在地址表中多次出现的真实地址。

如果你同意的话;很好。

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

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

【讨论】:

  • 这个答案是有道理的,只是它似乎忽略了实际发布的模型代码 ;-) 其中 ForeignKeys to Address 位于 UserProfile 和 Department 上,这意味着它们中的每一个都只能有一个地址,但一个地址可能由许多实体拥有。
  • 该死的我的速读能力很差...卡尔 - 像往常一样 - 是对的。我会更正我的答案。值得 -1,谢谢。
猜你喜欢
  • 2011-11-16
  • 1970-01-01
  • 2010-09-16
  • 2017-01-10
  • 1970-01-01
  • 2019-09-19
  • 2011-11-25
  • 2013-06-01
  • 2011-09-16
相关资源
最近更新 更多