2012-08-02 85 views
3

我对Django非常陌生,现在我正试图理解抽象模型的用法。假设您正在撰写博客服务,并且您希望经过身份验证的用户和匿名用户都能够评论博客帖子。在一对多中制作模型参考抽象模型

虽然方案是通过验证的用户(只是有一个外键引用一个特定的用户)非常容易的,它不是那么简单,当Authors不只是User秒,但无论是AnonymousAuthor S或RegisteredAuthor秒。

直接的方法在这里是建筑类层次:

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可以帮助在这里。但它是唯一的解决方案吗?感觉像过度杀伤。

+1

通用关系可能是最好的解决方案(想想你的外键关系如何在数据库中实现)。 – thebjorn 2012-08-02 19:19:11

回答

4

通用关系是为许多人创建外键的解决方案,与模型不同。通常,与继承,如果您有:

class Animal(models.Model): 
    ... 

class Dog(Animal): 
    ... 

再后来:

models.ForeignKey(Animal) 

可以存储Dog为外键一样好,因为Dog是-A Animal。但是,对于抽象类,这些不适合作为外键的目的地,因为它们不存在存在。 Django的“抽象”模型更接近“mixin”的定义:它们从来不会自行实例化,而是用于组成其他实例化的类。

所以,你有三个选择在这里:

  1. 变化Author到一个标准的模式,而不是抽象的。然后你可以创建外键到Author并通过Author你的任何子类。

  2. 使用通用外键

  3. 不要分手的模型摆在首位。

这里的最后的选择实际上是你最好的选择,因为没有理由有单独的作者表时,唯一的定义不同的是他们是否被注册或匿名。这是一个对象的状态,而不是不同类型的对象。就像不像BlueCar类那样。你有一个Car类,而“蓝色”是它的值color属性。

如果你坚持使用不同的型号。然后您可以使用代理模型。其中AnonymousAuthorRegisterAuthor只是Author的别名(它们没有自己的表),但具有别名可让您更改或添加自定义方法,特别是指定自定义管理器的功能,该管理器会自动过滤Author以仅返回“匿名”或“注册”类型。

+0

所以,你的意思是这里最好的解决方案就是拥有一个具有2个属性的'Author'类:'name'('CharField')和'user'(对特定用户的引用),当我需要渲染作者,我只需要显示'user.username',如果'用户'设置和'名称',否则?确切地说, – agibalov 2012-08-02 19:55:47

+0

。然后如果你想创建代理模型,你可以使用定制管理器来过滤'user__isnull',即'filter(user__isnull = True)'将返回“匿名”作者,而'filter(user__isnull = False)'将返回“注册“作者。显然,这也意味着'user'需要'null = True'。 – 2012-08-02 20:20:35