4

我对 Django 很陌生,现在我正在尝试了解抽象模型的使用。假设您正在编写一个博客服务,并且您希望经过身份验证的用户和匿名用户都能够评论博客文章。

虽然场景对于经过身份验证的用户来说非常简单(只有一个外键来引用特定用户),但当Authors不仅仅是Users 而是AnonymousAuthors 或RegisteredAuthors 时,情况就不是那么简单了。

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

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)
  ...

我喜欢这种方法,因为无论作者是谁,我都可以轻松地通过迭代BlogPostComments 集并调用display_name()每个评论来构建评论列表。这里唯一的问题是它不起作用。姜戈 说:

AssertionError: ForeignKey cannot define a relation with abstract class Author

这里有什么解决方案?

更新

我知道通用关系在这里可以提供帮助。但它是唯一的解决方案吗?感觉有点矫枉过正。

4

1 回答 1

6

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

class Animal(models.Model):
    ...

class Dog(Animal):
    ...

然后后来:

models.ForeignKey(Animal)

您也可以将 a 存储Dog为外键,因为 a Dogis-a Animal。但是,在抽象类的情况下,它们不适合被设置为外键的目标,因为它们不存在。Django 的“抽象”模型更接近于“mixin”的定义:它们永远不会被自己实例化,而是用来组成其他被实例化的类。

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

  1. 更改Author为标准模型而不是抽象模型。然后,您可以创建外键Author并传入Author您喜欢的任何子类。

  2. 使用通用外键

  3. 首先不要分解模型。

这里的最后一个选择实际上是您最好的选择,因为当唯一的区别在于它们是注册的还是匿名的时,没有理由拥有单独的作者表。那是对象的状态,而不是不同类型的对象。就像BlueCar上课一样是不合适的。你有一个Car类,而“蓝色”是它的color属性值。

如果您坚持使用单独的模型。然后,您可以使用代理模型。WhereAnonymousAuthorRegisterAuthor只是别名Author(他们没有自己的表),但是拥有别名允许您更改或添加自定义方法,特别是能够指定一个自定义管理器,该管理器自动过滤Author以仅返回“匿名”或“注册”类型,分别。

于 2012-08-02T19:31:03.003 回答