Django构建图片画廊模型:ManyToMany与ForeignKey选型咨询
Django图片画廊模型关系选型:ManyToMany还是ForeignKey?
需求与期望输出
要实现图片画廊功能,期望DRF返回如下格式的JSON数据:
[ { "id": 1, "owner": { "username": "drw", "first_name": "", "last_name": "", "avatar": "http://127.0.0.1:8000/media/default.png" }, "gallery": { "id": 4, "project_gallery": [ { "id": 1, "image": "http://127.0.0.1:8000/media/uploads/2022/8/9/drw/616da7a24f6856fab5dac79a_360_IT_Check_-_October_18th_2021_wUvme58.png", "thumbnail": null, "user": 1 }, { "id": 2, "image": "http://127.0.0.1:8000/media/uploads/2022/8/9/drw/Adapta-KDE-theme_vdDo0PO.webp", "thumbnail": null, "user": 1 }, { "id": 3, "image": "http://127.0.0.1:8000/media/uploads/2022/8/9/drw/Adapta-KDE-theme_ghZHmGF.webp", "thumbnail": null, "user": 1 } ], "project_gallery_name": "Testowo" }, "likes": [], "category": "ca1", "uuid": "30065e4d-3674-4f01-9861-307fe27ede13", "project_name": "Testowo", "comments": null } ]
现有模型代码
目前使用的模型如下:
class ImagesForGallery(models.Model): user = models.ForeignKey(UserProfile, null=True, blank=True, on_delete=models.CASCADE) image = models.ImageField(upload_to=user_directory_path, blank=True, null=True) thumbnail = models.ImageField(upload_to='uploads/', blank=True, null=True) def __str__(self): return 'User: {} || Image: {}'.format(self.user, self.image) class GalleryProject(models.Model): project_gallery_name = models.CharField(max_length=20, null=True, blank=True) project_gallery = models.ManyToManyField(ImagesForGallery, blank=True, related_name='project_gallery') def __str__(self): return '{}'.format(self.project_gallery_name)
选型分析
两种关系都能实现目标JSON格式,核心判断依据是业务逻辑:
1. 使用ForeignKey的场景
如果业务规则是一张图片只能属于一个画廊,用ForeignKey更合理,效率也更高(无需额外中间表)。调整后的模型如下:
class ImagesForGallery(models.Model): user = models.ForeignKey(UserProfile, null=True, blank=True, on_delete=models.CASCADE) # 添加外键关联画廊,related_name用于反向查询 gallery = models.ForeignKey('GalleryProject', on_delete=models.CASCADE, related_name='project_gallery') image = models.ImageField(upload_to=user_directory_path, blank=True, null=True) thumbnail = models.ImageField(upload_to='uploads/', blank=True, null=True) def __str__(self): return 'User: {} || Image: {}'.format(self.user, self.image) class GalleryProject(models.Model): project_gallery_name = models.CharField(max_length=20, null=True, blank=True) def __str__(self): return '{}'.format(self.project_gallery_name)
2. 保留ManyToMany的场景
如果业务规则是一张图片可以被多个画廊共享复用,现有ManyToMany的写法是正确的,无需调整模型。
序列化器实现(两种关系通用)
不管用哪种关系,都可以通过嵌套序列化器实现目标JSON格式,示例代码如下:
from rest_framework import serializers from .models import ImagesForGallery, GalleryProject, UserProfile # 用户信息序列化器 class UserProfileSerializer(serializers.ModelSerializer): class Meta: model = UserProfile fields = ['username', 'first_name', 'last_name', 'avatar'] # 图片序列化器 class ImagesForGallerySerializer(serializers.ModelSerializer): class Meta: model = ImagesForGallery fields = ['id', 'image', 'thumbnail', 'user'] # 画廊序列化器 class GalleryProjectSerializer(serializers.ModelSerializer): project_gallery = ImagesForGallerySerializer(many=True) class Meta: model = GalleryProject fields = ['id', 'project_gallery', 'project_gallery_name'] # 顶级项目序列化器(对应JSON根对象,需自行定义Project模型包含category、uuid等字段) class ProjectSerializer(serializers.ModelSerializer): owner = UserProfileSerializer() gallery = GalleryProjectSerializer() likes = serializers.ListField(default=[]) comments = serializers.NullBooleanField(default=None) class Meta: model = Project fields = ['id', 'owner', 'gallery', 'likes', 'category', 'uuid', 'project_name', 'comments']
总结:选型的关键是业务场景,而非输出格式——ForeignKey适合图片专属画廊,ManyToMany适合图片跨画廊共享。
内容的提问来源于stack exchange,提问作者DoDr
相关产品推荐
相关产品推荐

