有一个模型来与几个不同的模型相关联

时间:2016-06-21 00:30:45

标签: python django

我有一个简单的通知模型:

class Notification(models.Model):
    user = models.ForeignKey(User)
    sender = models.ForeignKey(User)
    model = '''What to put here?'''
    comment = models.CharField(max_length=200)
    created = models.DateTimeField(auto_now=False,auto_now_add=True)

我需要通知与几个不同的模型相关,例如;帖子,用户跟随等

在django中你是否可以与几个模型相关而不是为每个模型创建一个通知模型?

我想避免这样的模型: PostLikeNotification,UserFollowNotification等

django也有这个功能吗?我无法在文档中找到它。

3 个答案:

答案 0 :(得分:1)

您可以使用Content Types / Generic Relations

error: 'const class __gnu_cxx::__normal_iterator<const MyClassA<double>*, std::vector<MyClassA<double> > >' has no member named 'valA'

这里我们存储Notification模型中相关对象的模型(Using the Content Types framework)和主键(在本例中必须是整数),然后添加一个属性方法来获取相关对象。

通过此功能,您可以将通知与任何其他模型相关联。您还可以使用class Notification(models.Model): user = models.ForeignKey(User) sender = models.ForeignKey(User) object_id = models.PositiveIntegerField(default=None, null=True) content_type = models.ForeignKey(ContentType, default=None, null=True) comment = models.CharField(max_length=200) created = models.DateTimeField(auto_now=False,auto_now_add=True) @property def model_object(self): content_type = self.content_type object_id = self.object_id if content_type is not None and object_id is not None: MyClass = content_type.model_class() model_object = MyClass.objects.filter(pk=object_id) if model_object.exists(): return model_object.first() return None 字段上的ForeignKey.limit_choices_to参数来验证它是否只接受某些模型。

答案 1 :(得分:0)

Django需要在创建关系之前知道模型,您可以将模型存储在char字段中,如// Returns whether 'root' is a balanced tree. // Also stores the tree's height in *height. bool balanced_height(node* root, int* height) { // The trivial base case – an empty tree is balanced and has height 0. if (root == nullptr) { *height = 0; return true; } // Information gathering using recursion: // Find out whether the subtrees are balanced, and get their heights. int leftheight = 0; int rightheight = 0; bool leftbalance = balanced_height(root->left, &leftheight); bool rightbalance = balanced_height(root->right, &rightheight); // Now that we know the heights of the subtrees, we can store the height of this tree. *height = max(leftheight, rightheight) + 1; // Finally, a translation into C++ of the definition: // A tree is balanced if and only if // - the subtrees are balanced, and // - the heights of the subtrees differ by at most one. return leftbalance && rightbalance && abs(leftheight - rightheight) <= 1; } bool balanced(node* root) { int height = 0; return balanced_height(root, &height); } post:23,并定义一个user_follow:41方法,该方法将解析该字段并返回正确的模型对象

答案 2 :(得分:0)

一切都取决于您的设计,您有几种选择。不同的选项取决于数据库的大小:

  • 有多少通知?
  • 您是否需要经常更新通知?
  • 或者大多数通知都会插入一次,然后经常阅读?

使用抽象模型

使用抽象模型并实际创建PostLikeNotificationUserFollowNotification以及此类其他模型。

class Notification(models.Model):
    # ...
    class Meta:
        abstract = True

class PostLikeNotification(Notification):
    model = models.ForeignKey(SomePost)

class UserFollowNotification(Notifcation):
    model = models.ForeignKey(Follower)

# ...

这有几个好处:

  • 您将关系保存在(关系型)数据库中。
  • 您有强大的外键来防止数据不一致。
  • 这是&#34; Djangoic&#34;:数据库中的关系,从规范化数据库开始,没有早期优化是{{​​1}}的做事方式。

当然,这有一些缺点:

  • 如果您需要搜索所有通知,则查询将会很复杂。
  • 此外,对所有通知的查询都会很慢,因为它会过滤几个表。

使用CharField

您可以使用简单的django并在其中存储模型名称和ID。或两个字段一个用于名称,另一个用于id。

CharField

优点:

  • 您有一个表,如果您有正确的索引,查询会更快。
  • 您可以通过简单的比较获得其中一种通知(索引class Notification(models.Model): model_type = models.CharField(max_len=48) model_id = models.PositiveInteger() 以获得额外的速度)。

缺点:

  • 可能会出现不一致的数据。
  • 您需要在更高级别添加额外代码以处理可能存在的不一致数据。
  • 并行写入(可能需要锁定整个表)可能是个问题。

中间地带,使用几个外键

这只是在以下两个选项之间实现中间地带的方式:添加几个可以为空的外键。其他实现中间立场的方式也存在。

model_type

优势:

  • 可以在不搜索其他表的情况下验证不一致的数据(外键是外键,数据库会考虑它们的一致性。)

缺点:

  • 它有其他两种方法的大多数缺点,但程度较小(至少在大多数方法中)。

结论

如果您刚刚开始一个项目,并且您不知道(或者不担心)数据量,那么会创建多个表。为此目的创建了抽象模型。

另一方面,如果您要阅读和过滤大量通知(很多,我的意思是数百万),那么您有充分的理由创建单个通知表并在更高级别处理关系。请注意,这会导致锁定问题,如果您有一个表,则(几乎)永远不会锁定通知。