问题
I have a table called Post. A post can have 2 videos or 2 images, but not both. The table schema for a post looks like this:
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
header = models.CharField()
created_at = models.DateTimeField(auto_now_add=True)
I have two tables that look similar to each other:
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()
How do I create and enforce the relationship where a post can have maximum and minimum of 2 images or 2 videos, but it can't have both videos and images at the same time? Or is there a better way to do this?
回答1:
Probably you can write a Mixin
class like this:
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()
But rather than handling them in model, you should handle them in forms or serializers(if you are using DRF).
回答2:
Another method is to add a pre_save
signal for both PostImage
and PostVideo
and check your conditions there:
@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!')
来源:https://stackoverflow.com/questions/59403910/django-two-table-relationship-but-not-both