我想创建一个包含 FileField
的 Django 模型来存储图像和视频文件,但我想在保存实例之前验证这些文件。我想过添加三个字段:
file
:FileField
字段。这只会用于在数据库中有 file
列,但序列化程序不会使用它(而是使用接下来的两个字段)。file_image
:执行图像文件验证的 ImageField
。在保存模型实例之前,该文件将分配给 file
字段。 我不希望此字段具有 dabatase 表示。file_video
:用于执行视频文件验证的 VideoField
(自定义字段)。在保存模型实例之前,该文件将分配给 file
字段。 我不希望此字段具有 dabatase 表示。当然,file_image
和 file_video
不会同时设置。
问题阻止 makemigrations
在迁移中包含 file_image
和 file_video
。我可以手动编辑迁移文件,但我想知道是否有任何方法可以自动忽略这些字段。
class MyModel(models.Model):
file = models.ImageField()
file_image = models.ImageField() # Not an actual column
file_video = models.VideoField() # Not an actual column
def save(self, *args, **kwargs):
if self.file_image.file is not None:
self.file.file = self.file_image.file
elif self.file_video.file is not None:
self.file.file = self.file_video.file
else:
raise ValidationError()
super().save(*args, **kwargs)
答案 0 :(得分:2)
您的模型代表了数据库中的内容。我建议你不要以这种方式对抗 ORM。相反,我会在创建/更新实例时使用的表单类中执行验证。使用表单,您可以定义字段 file_video
和 file_image
,然后使用该字段写入 file
。
答案 1 :(得分:0)
好的,所以我放弃了向模型添加额外字段的最初想法,我只留下了 file
字段,正如@schillingt 所建议的那样。现在我在 clean()
方法中使用自定义验证来验证文件类型。
from django.db import models
from django.db.models.fields.files import ImageFieldFile
from django import forms
from custom_fields import forms as custom_forms
from custom_fields import fields as custom_fields
class MyModel(models.Model):
file = models.ImageField()
def clean(self):
# Get the MIME type to have a hint of the file type
import magic
mime_type = magic.from_buffer(self.file.file.read(1024), mime=True)
if mime_type.startswith('image'):
image_field = ImageFieldFile(self, models.ImageField(),
self.file.name)
image_field.file = self.file.file
if image_field.width:
self.width = image_field.width
self.height = image_field.height
self.media_type = mime_type
else:
raise ValidationError({'file': forms.ImageField.
default_error_messages['invalid_image']})
elif mime_type.startswith('video'):
video_field = custom_fields.VideoFieldFile(self,
custom_fields.VideoField(),
self.file.name)
video_field.file = self.file.file
if video_field.width:
self.width = video_field.width
self.height = video_field.height
self.duration = video_field.duration
self.media_type = mime_type
else:
raise ValidationError({'src': custom_forms.VideoField.
default_error_messages['invalid_video']})
else:
raise ValidationError({'src': 'The file is neither an image nor a video.'})
def save(self, *args, **kwargs):
self.full_clean()
super().save(*args, **kwargs)
我知道这是一个丑陋的解决方案,但这可行吗?我的意思是,我测试了它,它似乎有效,但肯定会有更好、更优雅的方法。