Django项目架构建议

时间:2020-03-02 15:00:47

标签: django django-models django-rest-framework django-views

我有一个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个用户,我想做最好的过滤器,将未读的帖子返回给用户

如果应该使用第一个选项,如何扩展用户模型? 谢谢!

3 个答案:

答案 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_atUserReadPost的{​​{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
相关问题