模型使用哪种模式具有不同的变化?通用FK,多表,继承,其他?

时间:2019-05-24 05:22:07

标签: django database django-models

我在决定如何为特定数据结构构建模型时遇到麻烦。

我拥有的模型是帖子,组,用户。

我希望可以从组页面或用户页面以及可能的更多页面(如事件页面)发布Post模式。

帖子将包含文本,图像(fk),用户,观看次数,评分(例如,来自-指向用户或群组页面中发布位置的引用)的字段,尽管我不确定如何建立此连接

我曾考虑过使用通用外键将字段分配给不同的模型,但阅读articles时建议避免使用它。我尝试了建议的模型,但是我不确定它们是否适合我的需求。

此刻,我选择了替代4-多表继承

class Group(models.Model):
    name = models.CharField(max_length=64)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='_groups')
    members = models.ManyToManyField(
        settings.AUTH_USER_MODEL)

    def __str__(self):
        return f'{self.name} -- {self.created_by}'

    def save(self, *args, **kwargs):
        # https://stackoverflow.com/a/35647389/1294405
        created = self._state.adding
        super(Group, self).save(*args, **kwargs)
        if created:
            if not self.members.filter(pk=self.created_by.pk).exists():
                self.members.add(self.created_by)


class Post(models.Model):
    content = models.TextField(blank=True, default='')
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_posts",
        related_query_name="%(app_label)s_%(class)ss")

    # class Meta:
    #     abstract = True

    def __str__(self):
        return f'{self.content} -- {self.created_by}'


class PostImage(models.Model):
    image = models.ImageField(upload_to=unique_upload)
    post = models.ForeignKey(
        Post, related_name='images', on_delete=models.CASCADE)

    def __str__(self):
        return '{}'.format(self.image.name)

class UserPost(models.Model):
    post = models.OneToOneField(
        Post, null=True, blank=True, related_name='_uPost', on_delete=models.CASCADE)


class GroupPost(models.Model):
    post = models.OneToOneField(
        Post, null=True, blank=True, related_name='_gPost', on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)

要做一些特定的过滤器,例如:

过滤特定的论坛帖子

Post.objects.filter(_gPost__group=group)

过滤特定的用户帖子

Post.objects.filter(created_by=user) # exclude groups with _gPost__isnull=False

为用户/组创建帖子

p = Post.objects.create(...)
up = UserPost.objects.create(post=p)
gp = GroupPost.objects.create(post=p)

真的,我想知道这是否是明智的选择。当前的过滤器和创建方式感觉很奇怪。因此,让我对这种方法犹豫不决的只是它的外观。

因此,Generic ForeignKey是此处或当前多表方法使用的地方。我尝试使用abstract = True进行继承,但由于我需要外键来建立帖子模型,因此无法工作。即使没有摘要,我也获得了外键引用,但是过滤器变得令人沮丧。

编辑:

到目前为止,只有奇怪的问题(但不是真正的问题)在过滤时,我必须明确地排除某些字段以获取所需的内容,仅使用.filter(created_by=...)即可获取所有其他中间表。 不包括所有其他平板电脑的过滤器帖子将需要Post.objects.filter(_uPost__isnull=True, _gPost__isnull=True, _**__isnull=True),这可能最终很乏味。

2 个答案:

答案 0 :(得分:0)

我认为您的方法是明智的,这也许就是我的结构方式。

另一种方法是将Group和Event外键移到Post模型中,如果Post没有发布到组或事件中,则将它们设置为NULL / None。这样可以提高性能,并使过滤器更合理一些,但是如果您认为Posts可以在将来添加到许多其他模型中,那么我会避免这种方法(因为您必须不断添加越来越多的外键)。 / p>

答案 1 :(得分:0)

此刻,我将坚持目前的模式。

有兴趣的人可以阅读一些额外的内容。

https://www.slideshare.net/billkarwin/sql-antipatterns-strike-back/32-Polymorphic_Associations_Of_course_some