【问题标题】:Django: Using ImageFields in other apps?Django:在其他应用程序中使用 ImageFields?
【发布时间】:2019-04-03 16:13:22
【问题描述】:

我有一些上传图片的应用程序。现在几乎相同的代码在每个应用程序中多次出现,我希望从名为 images 的应用程序加载图像。是否可以连接其他应用以便它们使用 app1[images] ShareImage 类的 ImageFields?

如果没有,我该如何使用 image_resize 方法和两个@receiver 函数,以便它们可以被多个应用程序使用,而我只有一个代码:

我以前尝试过遗传,但我无法摆脱它。

我还尝试通过 Import 将 ImageFields 导入另一个类。

应用程序1:

import os

from io import BytesIO
from PIL import Image
from django.db import models
from django.dispatch import receiver
from django.core.files.base import ContentFile
from .storage import OverwriteStorage


class ShareImage(models.Model):
    image = models.ImageField(
        upload_to='images/',
        verbose_name='Bild',
        storage=OverwriteStorage(),
    )

    thumbnail = models.ImageField(
        upload_to='images/',
        editable=False,
        storage=OverwriteStorage(),
    )

    def save(self, *args, **kwargs):
        if not os.path.exists(self.image.path) and not self.images_resize():
            raise Exception('Error: Thumbnail not created')

        super(ShareImage, self).save(*args, **kwargs)

    def images_resize(self):
        size = (288, 162)

        image = Image.open(self.image)
        image.thumbnail(size, Image.ANTIALIAS)

        name, extension = os.path.splitext(self.image.name)
        # to prevent django from creating new folders incorrectly
        name = os.path.basename(name)
        extension = extension.lower()
        file_name = name + '_thumbnail' + extension

        if extension in ['.jpg', '.jpeg']:
            file_extension = 'JPEG'
        elif extension == '.png':
            file_extension = 'PNG'
        elif extension == '.gif':
            file_extension = 'GIF'
        else:
            raise Exception('Error: Files extension not supported')

        temp = BytesIO()
        image.save(temp, file_extension)
        temp.seek(0)

        if not os.path.exists(self.image.path):
            self.thumbnail.save(
                file_name, ContentFile(temp.read()), save=False
            )
            return True


@receiver(models.signals.post_delete, sender=ShareImage)
def auto_delete_images_on_delete(instance, **kwargs):
    if instance.image:
        if os.path.isfile(instance.image.path):
            os.remove(instance.image.path)

    if instance.thumbnail:
        if os.path.isfile(instance.thumbnail.path):
            os.remove(instance.thumbnail.path)


@receiver(models.signals.pre_save, sender=ShareImage)
def auto_delete_images_on_change(instance, **kwargs):
    if not instance.pk:
        return False

    try:
        old_image = ShareImage.objects.get(pk=instance.pk).image
        old_thumb = ShareImage.objects.get(pk=instance.pk).thumbnail
    except ShareImage.DoesNotExist:
        return False

    new_image = instance.image
    new_thumb = instance.thumbnail

    if old_image != new_image:
        if os.path.isfile(old_image.path):
            os.remove(old_image.path)

    if old_thumb != new_thumb:
        if os.path.isfile(old_thumb.path):
            os.remove(old_thumb.path)

示例 app2:

import os

from io import BytesIO
from PIL import Image
from django.db import models
from django.dispatch import receiver
from django.core.files.base import ContentFile
from .storage import OverwriteStorage


class Logo(models.Model):
    title = models.CharField(max_length=100, unique=True, verbose_name='Titel')
    slug = models.SlugField(max_length=100, unique=True)
    created = models.DateTimeField(auto_now_add=True, verbose_name='Erstellt')
    updated = models.DateTimeField(auto_now=True, verbose_name='Aktualisiert')
    image = models.ImageField(upload_to='website/header/images/',
                              verbose_name='Bild', storage=OverwriteStorage())
    thumbnail = models.ImageField(upload_to='website/header/images/',
                                  editable=False, storage=OverwriteStorage())
    public = models.BooleanField(verbose_name='Öffentlich')

    class Meta:
        ordering = ['-updated']
        verbose_name = 'Logo'
        verbose_name_plural = 'Logos'

    def __str__(self):
        return self.title

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    您可以将ShareImage 设为abstract model,并从中继承其他类。例如:

    class ShareImage(models.Model):
       ...
       class Meta:
            abstract = True
    
    
    class Logo(ShareImage):
       ...
    

    这样,Logo 类将具有字段imagethumbnail。但这不会触发信号。

    另外,还有另一种方法,将ShareImage 作为OneToOneField 添加到Logo

    class Logo(models.Model):
        image = models.OneToOneField(ShareImage)
        ...
    
        def delete(self, *args, **kwargs):
            self.image.delete()
            return super(Logo, self).delete(*args, **kwargs)
    

    这样,ShareImage 的删除应该会触发这些信号。

    【讨论】:

    • 第一个解决方案就像你说的那样工作。这对我很有帮助。谢谢你。使用 OneToOneField 只有在 AdminPanel 中才有可能将其上传到 ShareImage 点上,然后使用 Logo 选择它,对吗?所以无法直接在 Logo 下上传?
    • 在其他应用程序中不能使用信号吗?
    • 您可以为这些应用创建新信号。或者您可以覆盖基本抽象模型的删除(不确定它是否会触发信号)。
    猜你喜欢
    • 1970-01-01
    • 2016-01-22
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 2015-06-17
    • 2020-05-10
    • 1970-01-01
    相关资源
    最近更新 更多