以一对多的方式制作模型参考抽象模型

Posted

技术标签:

【中文标题】以一对多的方式制作模型参考抽象模型【英文标题】:Make model reference abstract model in one-to-many 【发布时间】:2012-07-31 19:17:52 【问题描述】:

我对 Django 很陌生,现在我正在尝试了解抽象模型的使用。假设您正在编写一个博客服务,并且您希望经过身份验证的用户和匿名用户都能够评论博客帖子。

虽然对于经过身份验证的用户来说场景非常简单(只有一个外键来引用特定用户),但当 Authors 不仅仅是 Users 而是 AnonymousAuthors 或 RegisteredAuthors 时,情况就不是那么简单了.

这里的直接方法是构建类的层次结构:

class Author(models.Model):
  class Meta:
    abstract = True

class AnonymousAuthor(Author):
  name = models.CharField(max_length=128)
  def display_name(self):
    return self.name

class RegisteredAuthor(Author):
  user = models.ForeignKey(User)
  def display_name(self):
    return self.user.user_name

然后BlogPostComment可以这样定义:

class BlogPostComment(models.Model):
  author = models.ForeignKey(Author)
  ...

我喜欢这种方法,因为无论作者是谁,我都可以轻松地构建 cmets 列表,只需遍历 BlogPostComments 集并为它们中的每一个调用 display_name()。这里唯一的问题是它不起作用。 Django 说:

AssertionError: ForeignKey cannot define a relation with abstract class Author

这里有什么解决办法?

更新

我知道Generic relations 可以在这里提供帮助。但它是唯一的解决方案吗?感觉有点矫枉过正。

【问题讨论】:

泛型关系可能是最好的解决方案(想想你的外键关系将如何在数据库中实现)。 【参考方案1】:

与模型不同,通用关系是为许多人创建外键的解决方案。一般来说,如果你有继承:

class Animal(models.Model):
    ...

class Dog(Animal):
    ...

然后:

models.ForeignKey(Animal)

您也可以将Dog 存储为外键,因为Dog 就是Animal。但是,在抽象类的情况下,它们不适合设置为外键的目标,因为它们不存在。 Django 的“抽象”模型更接近于“mixin”的定义:它们永远不会被自己实例化,而是用来组成其他被实例化的类。

所以你在这里有三个选择:

    Author 更改为标准模型而不是抽象模型。然后,您可以为Author 创建外键并传入您喜欢的Author 的任何子类。

    使用通用外键

    首先不要分解模型。

这里的最后一个选择实际上是您最好的选择,因为没有理由拥有单独的作者表,唯一的区别是它们是注册的还是匿名的。那是一个对象的状态,而不是不同类型的对象。就像拥有 BlueCar 类这样的东西是不合适的。你有一个 Car 类,而“blue”是它的 color 属性的值。

如果您坚持使用单独的模型。然后,您可以使用代理模型。其中AnonymousAuthorRegisterAuthor 只是Author 的别名(它们没有自己的表),但拥有别名允许您更改或添加自定义方法,特别是指定自定义管理器的能力自动过滤 Author 以分别返回“匿名”或“注册”类型。

【讨论】:

所以,你的意思是这里最好的解决方案就是拥有一个具有 2 个属性的 Author 类:name (CharField) 和 user(参考特定用户)当我需要渲染作者时,如果设置了user,我只需要显示user.username,否则显示name 没错。然后,如果您想创建代理模型,您可以使用过滤user__isnull 的自定义管理器,即filter(user__isnull=True) 将返回“匿名”作者,而filter(user__isnull=False) 将返回“注册”作者。显然,这也意味着user 需要有null=True

以上是关于以一对多的方式制作模型参考抽象模型的主要内容,如果未能解决你的问题,请参考以下文章

Django - 以一对多关系更改相关对象的值

laravel 模型中的一对一,一对多,多对多的关联

MVC LINQ 查询以使用一对多和多对一表填充模型

Django 无法确定使用一对一关系链接一对多的查询集

Laravel5.1 模型--关联关系(复杂)

多表查询