Django双表关系,但不是两者都有

Django双表关系,但不是两者都有,django,django-models,Django,Django Models,我有一张叫波斯特的桌子。一篇文章可以有两个视频或两个图像,但不能同时有两个。post的表架构如下所示: class Post(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) header = models.CharField() created_at = models.DateTimeField(auto_now_add=Tru

我有一张叫波斯特的桌子。一篇文章可以有两个视频或两个图像,但不能同时有两个。post的表架构如下所示:

class Post(models.Model):
    user            = models.ForeignKey(User, on_delete=models.CASCADE)
    header          = models.CharField()
    created_at      = models.DateTimeField(auto_now_add=True)
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()
我有两张看起来很相似的桌子:

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()

如果一篇文章最多和最少可以有两张图片或两个视频,但不能同时有两张视频和两张视频,我如何创建和实施这种关系?或者有更好的方法来实现这一点吗?

也许您可以编写这样的
Mixin
类:

class Post(models.Model):
    user            = models.ForeignKey(User, on_delete=models.CASCADE)
    header          = models.CharField()
    created_at      = models.DateTimeField(auto_now_add=True)
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)。

另一种方法是为
PostImage
PostVideo
添加
pre\u 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!')
@receiver(预保存,发送方=后期视频)
@接收方(预保存,发送方=后期图像)
def post_验证器(发送方、实例、*args、**kwargs):
images\u count=instance.post.postimage\u set.count()
videos\u count=instance.post.postvideo\u set.count()
如果不是():
引发ValidationError('未满足条件!')

保存2张图像时,您可以检查此用户是否在PostVideo模型中有视频,反之亦然。或者,您只能创建一个模型,其中包含一个要发布的OneToOneField,并在此模型中创建将保存两个元素的arrayfield。@sandeep我将使用哪种保存方法编写此代码?保存后方法还是其他两种模式?如果使用第一种方法,请在保存图像/视频之前进行检查。但我认为你应该使用第二种方法。然后你不必检查任何东西,因为它是OneToOneField,你可以在ArrayField中保存两个元素(视频或图像)。我非常喜欢这个解决方案,但是,我如何在序列化程序中实现这样的东西?模型不应该限制这种情况在序列化程序中发生吗?它会限制它,但在我看来代码并不干净。IMHO验证应该在serializer中进行,因为它就是为了这个目的而存在的。非常抱歉,但是您如何为serializer编写这样的验证程序?您好,我实际上提出了一个新问题,其中包含了我试图创建的内容的更深入的逻辑,您能看一下吗?我添加了序列化程序代码: