Python 使模型引用一对多中的抽象模型
我是Django的新手,现在我正在尝试理解抽象模型的用法。假设您正在编写一个博客服务,您希望经过身份验证的用户和匿名用户都能够评论博客文章 虽然这种情况对于经过身份验证的用户来说非常简单(只有一个外键来引用特定的用户),但当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
作者不仅仅是用户,而是匿名作者
或注册作者
时,情况就不那么简单了
这里的直接方法是构建类的层次结构:
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
。