Python 使模型引用一对多中的抽象模型

Python 使模型引用一对多中的抽象模型,python,django,django-models,foreign-keys,abstract-class,Python,Django,Django Models,Foreign Keys,Abstract Class,我是Django的新手,现在我正在尝试理解抽象模型的用法。假设您正在编写一个博客服务,您希望经过身份验证的用户和匿名用户都能够评论博客文章 虽然这种情况对于经过身份验证的用户来说非常简单(只有一个外键来引用特定的用户),但当作者不仅仅是用户,而是匿名作者或注册作者时,情况就不那么简单了 这里的直接方法是构建类的层次结构: class Author(models.Model): class Meta: abstract = True class AnonymousAuthor(Aut

我是Django的新手,现在我正在尝试理解抽象模型的用法。假设您正在编写一个博客服务,您希望经过身份验证的用户和匿名用户都能够评论博客文章

虽然这种情况对于经过身份验证的用户来说非常简单(只有一个外键来引用特定的用户),但当
作者不仅仅是
用户,而是
匿名作者
注册作者
时,情况就不那么简单了

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

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
然后可以这样定义
blogposcomment

class BlogPostComment(models.Model):
  author = models.ForeignKey(Author)
  ...
我喜欢这种方法,因为无论作者是谁,只要迭代
blogposcomment
s集合并为每个集合调用
display\u name()
,我都可以轻松构建注释列表。这里唯一的问题是它不起作用。Django说:

AssertionError: ForeignKey cannot define a relation with abstract class Author
这里的解决方案是什么

更新


我知道这会有帮助。但这是唯一的解决办法吗?感觉有点过头了。

泛型关系是为许多模型创建外键的解决方案,与模型不同。一般来说,如果您有以下情况,请使用继承:

class Animal(models.Model):
    ...

class Dog(Animal):
    ...
后来:

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

这里有三种选择:

  • 将作者更改为标准模型,而不是摘要。然后,您可以为
    Author
    创建外键,并传入
    Author
    的任何子类

  • 使用通用外键

  • 首先不要破坏模型

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


    如果你坚持不同的型号。然后可以使用代理模型。其中,
    AnonymousAuthor
    RegisterAuthor
    只是
    Author
    的别名(它们没有自己的表),但拥有别名允许您更改或添加自定义方法,特别是能够指定一个自定义管理器,自动筛选
    Author
    ,只返回“匿名”或“已注册”类型。

    泛型关系可能是最佳解决方案(请考虑如何在数据库中实现外键关系)。因此,您的意思是,这里的最佳解决方案只是拥有一个具有两个属性的
    Author
    类:
    name
    CharField
    )和
    user
    (对特定用户的引用),当我需要呈现作者时,我只需要显示
    user。如果设置了
    user
    ,则显示username
    ,否则就显示
    name
    。如果你想创建代理模型,你可以使用自定义管理器过滤
    user\u isnull
    ,即
    过滤器(user\uu isnull=True)
    将返回“匿名”作者,而
    过滤器(user\uu isnull=False)
    将返回“注册”作者。显然,这也意味着
    user
    将需要
    null=True