以一对多的方式制作模型参考抽象模型
Posted
技术标签:
【中文标题】以一对多的方式制作模型参考抽象模型【英文标题】:Make model reference abstract model in one-to-many 【发布时间】:2012-07-31 19:17:52 【问题描述】:我对 Django 很陌生,现在我正在尝试了解抽象模型的使用。假设您正在编写一个博客服务,并且您希望经过身份验证的用户和匿名用户都能够评论博客帖子。
虽然对于经过身份验证的用户来说场景非常简单(只有一个外键来引用特定用户),但当 Authors
不仅仅是 User
s 而是 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)
...
我喜欢这种方法,因为无论作者是谁,我都可以轻松地构建 cmets 列表,只需遍历 BlogPostComment
s 集并为它们中的每一个调用 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
属性的值。
如果您坚持使用单独的模型。然后,您可以使用代理模型。其中AnonymousAuthor
和RegisterAuthor
只是Author
的别名(它们没有自己的表),但拥有别名允许您更改或添加自定义方法,特别是指定自定义管理器的能力自动过滤 Author
以分别返回“匿名”或“注册”类型。
【讨论】:
所以,你的意思是这里最好的解决方案就是拥有一个具有 2 个属性的Author
类:name
(CharField
) 和 user
(参考特定用户)当我需要渲染作者时,如果设置了user
,我只需要显示user.username
,否则显示name
?
没错。然后,如果您想创建代理模型,您可以使用过滤user__isnull
的自定义管理器,即filter(user__isnull=True)
将返回“匿名”作者,而filter(user__isnull=False)
将返回“注册”作者。显然,这也意味着user
需要有null=True
。以上是关于以一对多的方式制作模型参考抽象模型的主要内容,如果未能解决你的问题,请参考以下文章