我有一个django项目,并且有一个邮政模型女巫,像这样:
class BasicPost(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
published = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=False)
body = models.TextField(max_length=999)
media = models.ImageField(blank=True)
def get_absolute_url(self):
return reverse('basic_post', args=[str(self.pk)])
def __str__(self):
return self.title
此外,我使用基本django应用随附的基本用户模型。
我想保存每个用户已阅读的女巫帖子,以便将未读的帖子发送给他。 我的问题是最好的方法是,如果我使用“多对多”字段,应该将其放在“用户”模型上并保存他阅读的所有帖子,还是应该从另一个方向进行,将“多对多”字段中的Post模型并为每个女巫用户保存阅读的帖子吗? 在Post模型中,将有超过100万个帖子,大约有50,000个用户,我想做最好的过滤器,将未读的帖子返回给用户
如果应该使用第一个选项,如何扩展用户模型? 谢谢!
答案 0 :(得分:1)
您是否可以使用一个单独的ReadPost
模型,而不是一个可能很大的m2m模型(当用户阅读帖子时可以保存该模型)?这样,您只需查询ReadPost
模型即可获取数据,而不必将其全部存储在博客文章中。
也许是这样的:
from django.utils import timezone
class UserReadPost(models.Model):
user = models.ForeignKey("auth.User", on_delete=models.CASCADE, related_name="read_posts")
seen_at = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(BasicPost, on_delete=models.CASCADE, related_name="read_by_users")
您可以添加一个unique_together
约束以确保为每个用户和每个帖子仅创建一个UserReadPost
对象(以确保您没有两次计数),然后使用{{1 }}时创建新记录。
然后查找用户已阅读的帖子是:
get_or_create()
这也可以相对容易地扩展。例如,如果可以编辑posts = UserReadPost.objects.filter(user=current_user).values_list("post", flat=True)
对象,则可以在帖子中添加BasicPost
字段。然后,您可以将updated_at
字段的seen_at
与UserReadPost
的{{1}}字段进行比较,以检查他们是否看到了更新的版本。
缺点是您将在数据库中为此表创建很多行。
答案 1 :(得分:1)
关于第一个问题(走哪条路):我相信默认情况下,ManyToMany在数据库中同时为两个外键创建索引。因此,无论您在用户或BasicPost中的任何位置放置关系,都将通过索引来处理直接关系和反向关系。 Django将为您创建一个包含三列的数据透视表,例如:(id,user_id,basic_post_id)。对该表的每次访问都将通过user_id或basic_post_id进行索引,并检查是否存在唯一的一对夫妇(user_id,basic_post_id)(如果有)。因此,决定在100万个帖子集还是5万个帖子中进行过滤是您应用程序中更重要的事情。
关于第二个问题(如何使User重载),通常建议从一开始就将User子类化。如果为时已晚,并且您的项目太先进了,则可以在models.py中进行此操作:
class BasicPost(models.Model):
# your code
readers = models.ManyToManyField(to='User', related_name="posts_already_read")
# "manually" add method to User class
def _unread_posts(user):
return BasicPost.objects.exclude(readers__in=user)
User.unread_posts = _unread_posts
虽然没有运行此代码!希望这会有所帮助。
答案 2 :(得分:0)
如果您按时间顺序(例如,按created_at
放置帖子,则可以选择在latest_read_post_id
字段中extend user model。
这种情况:
class BasicPost(models.Model):
# your code
def is_read_by(self, user):
return self.id < user.latest_read_post_id