【问题标题】:Django two table relationship, but not bothDjango 两张表的关系,但不是两者都有
【发布时间】:2019-12-19 05:48:53
【问题描述】:

我有一个名为 Post 的表。一个帖子可以有 2 个视频或 2 个图像,但不能同时有。帖子的表架构如下所示:

class Post(models.Model):
    user            = models.ForeignKey(User, on_delete=models.CASCADE)
    header          = models.CharField()
    created_at      = models.DateTimeField(auto_now_add=True)

我有两张看起来很相似的表格:

class PostImage(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    img  = models.ImageField()


class PostVideo(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    video = models.FileField()

如何创建和强制执行这样的关系:帖子最多可以包含 2 个图像或 2 个视频,但不能同时包含视频和图像?或者有更好的方法吗?

【问题讨论】:

  • 保存2张图片时,可以检查该用户是否有PostVideo模式的视频,反之亦然。
  • 或者你可以只创建一个带有 OneToOneField 的模型来发布,并在这个模型中创建 arrayfield 来保存两个元素。
  • @sandeep 我将在哪种保存方法中编写此代码?后保存方法还是其他两种模型?
  • 如果您使用第一种方法,请在保存图像/视频之前检查。但我认为你应该使用第二种方法。那么您不必检查任何内容,因为它是 OneToOneField,您可以在 ArrayField 中保存两个元素(视频或图像)

标签: django django-models


【解决方案1】:

也许你可以像这样写一个Mixin 类:

class PostMixin(object):
    def save(self, *args, **kwargs):
        if hasattr(self, 'img') and self.post.images.exists():
             raise ValidationError('Already have an image')
        elif hasattr(self, 'video') and self.post.videos.exists():
             raise ValidationError('Already have a video')
        super(PostMixin, self).save(*args, **kwargs)

class PostImage(PostMixin, models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="images")
    img  = models.ImageField()


class PostVideo(PostMixin, models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="videos")
    video = models.FileField()

但不是在模型中处理它们,您应该在表单或序列化程序中处理它们(如果您使用的是 DRF)。

【讨论】:

  • 我真的很喜欢这个解决方案,但是,我将如何在序列化程序中实现这样的东西?模型不应该限制这种情况在序列化程序中发生吗?
  • 它会限制它,但我认为代码并不干净。恕我直言,验证应该在序列化程序中完成,因为它是为此目的而存在的。
  • 非常抱歉,您如何为序列化程序编写这样的验证器?
  • 嗨,我实际上提出了一个新问题,对我正在尝试创建的内容进行了更深入的逻辑,你能看一下吗?我添加了我的序列化程序代码:stackoverflow.com/questions/59406141/…
【解决方案2】:

另一种方法是为PostImagePostVideo 添加一个pre_save 信号并检查那里的条件:

@receiver(pre_save, sender=PostVideo)
@receiver(pre_save, sender=PostImage)
def post_validator(sender, instance, *args, **kwargs):
    images_count = instance.post.postimage_set.count()
    videos_count = instance.post.postvideo_set.count()
    if not (<your conditions met>):
        raise ValidationError('Conditions not met!')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-01
    • 2020-10-12
    • 1970-01-01
    相关资源
    最近更新 更多