使用通过django-admin上传的文件的元数据填充模型



我有两个型号,FotoFotoMetadataFoto只有一个名为upload的属性,即upload字段。FotoMetadata具有一些属性,并且应当从在Foto上传的foto接收元数据。这可以在管理员界面手动完成,但我想自动完成,即:当照片通过管理员界面上传时,FotoMetadata会自动填充。

在我的模型.py中,我有几个类,包括Foto和FotoMetadata:

class Foto(models.Model):
    upload = models.FileField(upload_to="fotos")
    def __str__(self):
        return '%s' %(self.upload)
class FotoMetadata(models.Model):
    image_formats = (
        ('RAW', 'RAW'),
        ('JPG', 'JPG'),
    )
    date = models.DateTimeField()
    camera = models.ForeignKey(Camera, on_delete=models.PROTECT)
    format =  models.CharField(max_length=8, choices=image_formats)
    exposure = models.CharField(max_length=8)
    fnumber = models.CharField(max_length=8)
    iso = models.IntegerField()
    foto = models.OneToOneField(
        Foto,
        on_delete=models.CASCADE,
        primary_key=True,
    )

当我登录到管理站点时,我有一个与Foto相关的上传表单,这很好。我的问题是,我不能在FotoMetadata上插入元数据。我做了一个函数来解析照片,并给我一本字典,里面有我需要的信息。此函数名为GetExif,位于名为GetExif.py的文件中。这将是它的简化版本:

def GetExif(foto):
    # Open image file for reading (binary mode)
    f = open(foto, 'rb')
    # Parse file
    ...
    <parsing code>
    ...
    f.close()
    #create dictionary to receive data
    meta={}
    meta['date'] = str(tags['EXIF DateTimeOriginal'].values)
    meta['fnumber'] = str(tags['EXIF FNumber'])
    meta['exposure'] = str(tags['EXIF ExposureTime'])
    meta['iso'] = str(tags['EXIF ISOSpeedRatings'])
    meta['camera'] =str( tags['Image Model'].values)
    return meta

所以,基本上,我想做的是在admin.py上使用这个功能,在Foto上传照片时自动填充FotoMetadata,但我真的不知道如何制作。有人知道吗?


编辑2016年3月24日

好吧,在经历了更多的失败之后,我尝试在admin.py:中使用save_model

from django.contrib import admin
from .models import Autor, Camera, Lente, Foto, FotoMetadata
from fotomanager.local.getexif import GetExif
admin.site.register(Autor)
admin.site.register(Camera)
admin.site.register(Lente)
admin.site.register(FotoMetadata)
class FotoAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        # populate the model
        obj.save()
        # get metadata
        metadados = GetExif(obj.upload.url)
        # Create instance of FotoMetadata
        fotometa = FotoMetadata()
        # FotoMetadata.id = Foto.id
        fotometa.foto = obj.pk
        # save exposure
        fotometa.exposure = metadados['exposure']
admin.site.register(Foto, FotoAdmin)

我以为它会起作用,或者我在将数据保存到模型中时会遇到问题,但实际上我在这之前就被卡住了。我得到了这个错误:

异常类型:FileNotFoundError异常值:
[Erno 2]没有这样的文件或目录:'http://127.0.0.1:8000/media/fotos/IMG_8628.CR2'异常位置:getexif中的/home/ricardo/Desenvolvimento/fotosite/fotomanager/local/getexif.py,第24行

我的GetExif函数无法读取文件,但是,文件路径是正确的!如果我复制并粘贴到我的浏览器,它会下载文件。我正试图找出一种方法来更正地址,或者传递内部路径,或者将真实文件传递给函数,而不是它的路径。我也在考虑一种不同的方法来访问GetExif()函数中的文件。你知道怎么解决吗?


解决方案

我解决了上面的问题!通过阅读FileField源代码,我发现了一个名为path的属性,它解决了这个问题。我还做了一些其他修改,代码正在运行。admin.py上的FotoAdmin类现在是这样的:

class FotoAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        # populate the model
        obj.save()
        # get metadata
        metadados = GetExif(obj.upload.path)
        # Create instance of FotoMetadata
        fotometa = FotoMetadata()
        # FotoMetadata.id = Foto.id
        fotometa.foto = obj
        # set and save exposure
        fotometa.exposure = metadados['exposure']
        fotometa.save()

我还必须在模型.py中的一些属性上设置null=True,一切都正常工作。

我想您想启用postrongave信号读取:django信号

激活postrongave信号,这样在保存FOTO之后,您就有了一个钩子来做其他事情,在您的情况下解析photometa并创建一个FotoMetadata实例。

此外,如果您希望仅在fometema成功的情况下保存foto,或者您可能使用的任何其他条件,请预先保存信号,并仅在保存meta foto后保存foto。

最新更新