我对Django很新,现在我正在努力理解抽象模型的使用。假设您正在编写博客服务,并且您希望经过身份验证的用户和匿名用户能够对博客帖子发表评论。
虽然对于经过身份验证的用户来说情况非常简单(只有外键可以引用特定用户),但Authors
不仅仅是User
而是AnonymousAuthor
,这并不是那么简单。 s或RegisteredAuthor
s。
这里的直接方法是构建类的层次结构:
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)
...
我喜欢这种方法,因为无论作者是谁,我都可以通过迭代BlogPostComment
集并为每个集调用display_name()
来轻松构建注释列表。这里唯一的问题是它不起作用。 Django说:
AssertionError: ForeignKey cannot define a relation with abstract class Author
这里的解决方案是什么?
更新
我知道Generic relations可以在这里提供帮助。但它是唯一的解决方案吗?感觉像是矫枉过正。
答案 0 :(得分:5)
与模型不同,通用关系是为许多人创建外键的解决方案。一般来说,如果你有继承:
class Animal(models.Model):
...
class Dog(Animal):
...
然后是:
models.ForeignKey(Animal)
您也可以将Dog
存储为外键,因为Dog
是一个Animal
。但是,在抽象类的情况下,这些不适合设置为外键的目标,因为它们不存在 。 Django的“抽象”模型更接近于“mixin”的定义:它们从不单独实例化,而是用于组成其他实例化的类。
所以你有三个选择:
将Author
更改为标准模型而非抽象。然后,您可以创建Author
的外键并传入您喜欢的Author
的任何子类。
使用通用外键
首先不要拆分模型。
这里的最后一个选择实际上是你最好的选择,因为当唯一的定义差异是他们是注册还是匿名时,没有理由拥有单独的作者表。这是对象的状态,而不是不同类型的对象。就像拥有类似BlueCar
类的东西一样不合适。您有一个Car
类,而“蓝色”则是color
属性的值。
如果你坚持使用不同的型号。然后,您可以使用代理模型。 AnonymousAuthor
和RegisterAuthor
只是Author
的别名(他们没有自己的表),但是使用别名可以更改或添加自定义方法,特别是能力指定自动过滤Author
以仅分别返回“匿名”或“已注册”类型的自定义管理器。