在一对多中制作模型参考抽象模型

And*_*lov 4 python django abstract-class foreign-keys django-models

我是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
Run Code Online (Sandbox Code Playgroud)

然后BlogPostComment可以这样定义:

class BlogPostComment(models.Model):
  author = models.ForeignKey(Author)
  ...
Run Code Online (Sandbox Code Playgroud)

我喜欢这种方法,因为无论作者是谁,我都可以通过迭代BlogPostComments set并调用display_name()每个注释来轻松构建注释列表.这里唯一的问题是它不起作用.Django说:

AssertionError: ForeignKey cannot define a relation with abstract class Author
Run Code Online (Sandbox Code Playgroud)

什么是解决方案?

更新

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

Chr*_*att 5

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

class Animal(models.Model):
    ...

class Dog(Animal):
    ...
Run Code Online (Sandbox Code Playgroud)

然后是:

models.ForeignKey(Animal)
Run Code Online (Sandbox Code Playgroud)

您也可以将a存储Dog为外键,因为a Dog是a Animal.但是,在抽象类的情况下,这些不适合设置为外键的目标,因为它们不存在.Django的"抽象"模型更接近于"mixin"的定义:它们从不单独实例化,而是用于组成实例化的其他类.

所以你有三个选择:

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

  2. 使用通用外键

  3. 首先不要分解模型.

这里的最后一个选择实际上是你最好的选择,因为当唯一的定义差异是它们是注册还是匿名时,没有理由拥有单独的作者表.这是对象的状态,而不是不同类型的对象.就像拥有像BlueCar课一样的东西是不合适的.你有一个Car类,而"蓝色"是它的color属性的值.

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