Python django imagekit在ImageCacheFile默认函数中引发AttributeError异常

Python django imagekit在ImageCacheFile默认函数中引发AttributeError异常,python,django,django-admin,django-imagekit,django-photologue,Python,Django,Django Admin,Django Imagekit,Django Photologue,我正在使用以下组件进行一个项目: django:v2.2.10 django播客:1.3.2 django imagekit:4.0.2 django photologue:3.11 当我尝试添加新的播客节目时,我收到以下错误消息: 属性错误位于/admin/podcast/show/add/ 以下是完整的堆栈跟踪: Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. Inte

我正在使用以下组件进行一个项目:

django:v2.2.10

django播客:1.3.2

django imagekit:4.0.2

django photologue:3.11

当我尝试添加新的播客节目时,我收到以下错误消息:

属性错误位于/admin/podcast/show/add/

以下是完整的堆栈跟踪:

Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Internal Server Error: /admin/podcasting/show/add/
Traceback (most recent call last):
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/cachefiles/__init__.py", line 37, in __init__
    name = generator.cachefile_name
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/specs/__init__.py", line 95, in cachefile_name
    return fn(self)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/cachefiles/namers.py", line 40, in source_name_as_path
    '%s%s' % (generator.get_hash(), ext)))
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/specs/__init__.py", line 134, in get_hash
    self.source.name,
  File "/path/to/project/env/lib/python3.6/site-packages/photologue/models.py", line 345, in __getattr__
    raise AttributeError
AttributeError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/path/to/project/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/path/to/project/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/path/to/project/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/contrib/admin/options.py", line 606, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/contrib/admin/sites.py", line 223, in inner
    return view(request, *args, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/contrib/admin/options.py", line 1645, in add_view
    return self.changeform_view(request, None, form_url, extra_context)
  File "/path/to/project/env/lib/python3.6/site-packages/django/utils/decorators.py", line 45, in _wrapper
    return bound_method(*args, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/django/contrib/admin/options.py", line 1529, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "/path/to/project/env/lib/python3.6/site-packages/django/contrib/admin/options.py", line 1572, in _changeform_view
    self.save_model(request, new_object, form, not add)
  File "/path/to/project/env/lib/python3.6/site-packages/django/contrib/admin/options.py", line 1088, in save_model
    obj.save()
  File "/path/to/project/env/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
    force_update=force_update, update_fields=update_fields)
  File "/path/to/project/env/lib/python3.6/site-packages/django/db/models/base.py", line 790, in save_base
    update_fields=update_fields, raw=raw, using=using,
  File "/path/to/project/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
    for receiver in self._live_receivers(sender)
  File "/path/to/project/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
    for receiver in self._live_receivers(sender)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/specs/sourcegroups.py", line 33, in receiver
    fn(self, sender=sender, **kwargs)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/specs/sourcegroups.py", line 102, in post_save_receiver
    attname)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/specs/sourcegroups.py", line 124, in dispatch_signal
    signal.send(sender=source_group, source=file)
  File "/path/to/project/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
    for receiver in self._live_receivers(sender)
  File "/path/to/project/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
    for receiver in self._live_receivers(sender)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/registry.py", line 115, in source_group_receiver
    file = ImageCacheFile(spec)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/cachefiles/__init__.py", line 40, in __init__
    name = fn(generator)
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/cachefiles/namers.py", line 91, in hash
    '%s%s' % (generator.get_hash(), ext)))
  File "/path/to/project/env/lib/python3.6/site-packages/imagekit/specs/__init__.py", line 134, in get_hash
    self.source.name,
  File "/path/to/project/env/lib/python3.6/site-packages/photologue/models.py", line 345, in __getattr__
    raise AttributeError
AttributeError
[16/Mar/2020 22:47:47] "POST /admin/podcasting/show/add/ HTTP/1.1" 500 221587
photologue/models.py /path/to/django播客/podcast/models.py
@python\u 2\u unicode\u兼容
课堂展示(models.Model):
"""
播客节目,有很多插曲。
"""
显式_选择=(
(1)是,
(2、“(否”),
(三)清洁,
)
uuid=UUIDField(uid),unique=True)
created=models.DateTimeField(u(“created”)、auto\u now\u add=True、editable=False)
updated=models.DateTimeField(u(“更新”),auto_now=True,editable=False)
published=models.DateTimeField(quo(“published”),null=True,blank=True,editable=False)
sites=models.ManyToManyField(Site,verbose\u name=uu('sites'))
ttl=models.PositiveIntegerField(
_(“ttl”),默认值为1440,
help_text=\u(“生存时间”)频道可以播放的分钟数
刷新前已缓存。“”))
所有者=models.ForeignKey(
settings.AUTH\u USER\u MODEL,在\u delete=models.CASCADE上,相关的\u name=“podcast\u shows”,
详细名称=uu(“所有者”),
help_text=389;(““”确保用户帐户具有名称和电子邮件地址。”“”)
editor_email=models.EmailField(
_(“编辑电子邮件”),blank=True,
help_text=(负责提要内容的人的电子邮件地址)
网站管理员_email=models.EmailField(
_(“网站管理员电子邮件”),blank=True,
help_text=u(“负责频道发布的人员的电子邮件地址”)
如果settings.INSTALLED\u应用程序中有“许可证”:
license=models.ForeignKey(license,on_delete=models.CASCADE,verbose_name=u(“license”))
其他:
license=models.CharField(
_(“许可证”),最大长度=255,
help_text=_(“要将播客发布到iTunes,需要设置许可证类型。”)
organization=models.CharField(
_(“组织”),最大长度=255,
help_text=u(“制作播客的组织、公司或网站的名称”)
link=models.URLField(u(“link”),help\u text=u(“URL”)主网站或
主网站的播客部分。”“”)
enable_comments=models.BooleanField(默认值=True)
author\u text=models.CharField(
_(“作者文本”),最大长度为255,帮助文本为
此标记包含最受欢迎的个人或公司的名称
广泛归因于发布播客,并将
显示在播客标题的正下方。
建议的格式是:'email@example.com(全名)"
但仅“全名”是可以接受的。多个作者
应以逗号分隔。“”))
title=models.CharField(u(“title”),最大长度=255)
slug=AutoSlugField(u(“slug”),填充自=“title”,unique=“True”)
subtitle=models.CharField(
_(“副标题”),最大长度为255,
help_text=u(“如果只有几句话,比如一句标语,看起来就最好了。”)
#如果该节目不在iTunes上,用户表单中的许多字段可能会被忽略
在itunes=models.BooleanField上(
_(“iTunes”),默认值为True,
help_text=(如果播客已提交到iTunes,则选中此选项)
description_pretty=models.TextField(
_(“漂亮的描述”),blank=True,
help_text=“可能超过4000个字符,并包含HTML标记和样式。”)
description=models.TextField(
_(“说明”),最大长度为4000,帮助文本为
这是您告诉潜在订户您的所有信息的机会
描述你的主题,媒体格式,
节目时间表和其他相关信息,以便
知道他们订阅后会得到什么
此外,列出最相关的搜索词
您希望您的P播客与之匹配,然后将其构建到
请注意,iTunes删除了
在itunes:summary中包括不相关的单词列表,
描述,或itunes:关键字标签。此字段可以向上显示
到4000个字符。”“”)
如果settings.INSTALLED_应用程序中的“photologue”:
原始图片=models.ForeignKey(照片,on\u delete=models.CASCADE,verbose\u name=(“图像”),默认值=None,null=True,blank=True,help\u text=(“图像”)
播客必须具有1400 x 1400像素的JPG或PNG封面艺术
使用RGB颜色空间格式化。有关详细信息,请参阅我们的技术规范
详细信息。要有资格在iTunes商店中展示,
选择一个有吸引力的、原始的、方形的JPEG(.jpg)或
大小为1400x1400像素的PNG(.PNG)图像。该图像
将在iTunes中缩小到最小50x50像素。
有关参考信息,请参见
在iTunes中显示,图像必须在
附件上载!“”)
其他:
原始图像=图像字段(
_(“图像”),上载到=获取\显示\上载\文件夹,空白=真,帮助\文本=“”
播客必须具有1400 x 1400像素的JPG或PNG封面艺术
使用RGB颜色空间格式化。有关详细信息,请参阅我们的技术规范
详细信息。要有资格在iTunes商店中展示,
选择一个有吸引力的、原始的、方形的JPEG(.jpg)或
大小为1400x1400像素的PNG(.PNG)图像。该图像
将在iTunes中缩小到最小50x50像素。
有关参考信息,请参见
在iTunes中显示,i
class ImageCacheFile(BaseIKFile, ImageFile):
    """
    A file that represents the result of a generator. Creating an instance of
    this class is not enough to trigger the generation of the file. In fact,
    one of the main points of this class is to allow the creation of the file
    to be deferred until the time that the cache file strategy requires it.

    """
    def __init__(self, generator, name=None, storage=None, cachefile_backend=None, cachefile_strategy=None):
        """
        :param generator: The object responsible for generating a new image.
        :param name: The filename
        :param storage: A Django storage object that will be used to save the
            file.
        :param cachefile_backend: The object responsible for managing the
            state of the file.
        :param cachefile_strategy: The object responsible for handling events
            for this file.

        """
        self.generator = generator

        if not name:
            try:
                name = generator.cachefile_name
            except AttributeError:
                fn = get_by_qname(settings.IMAGEKIT_CACHEFILE_NAMER, 'namer')
                name = fn(generator)
        self.name = name

        storage = storage or getattr(generator, 'cachefile_storage',
            None) or get_singleton(settings.IMAGEKIT_DEFAULT_FILE_STORAGE,
            'file storage backend')
        self.cachefile_backend = (
            cachefile_backend
            or getattr(generator, 'cachefile_backend', None)
            or get_singleton(settings.IMAGEKIT_DEFAULT_CACHEFILE_BACKEND,
                             'cache file backend'))
        self.cachefile_strategy = (
            cachefile_strategy
            or getattr(generator, 'cachefile_strategy', None)
            or get_singleton(settings.IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY,
                             'cache file strategy')
        )

        super(ImageCacheFile, self).__init__(storage=storage)
class ImageModel(models.Model):
     # ...
    
    def __getattr__(self, name):
        global size_method_map
        if not size_method_map:
            init_size_method_map()
        di = size_method_map.get(name, None)
        if di is not None:
            result = partial(getattr(self, di['base_name']), di['size'])
            setattr(self, name, result)
            return result
        else:
            raise AttributeError
@python_2_unicode_compatible
class Show(models.Model):
    """
    A podcast show, which has many episodes.
    """
    EXPLICIT_CHOICES = (
        (1, _("yes")),
        (2, _("no")),
        (3, _("clean")),
    )
    uuid = UUIDField(_("id"), unique=True)

    created = models.DateTimeField(_("created"), auto_now_add=True, editable=False)
    updated = models.DateTimeField(_("updated"), auto_now=True, editable=False)
    published = models.DateTimeField(_("published"), null=True, blank=True, editable=False)

    sites = models.ManyToManyField(Site, verbose_name=_('Sites'))

    ttl = models.PositiveIntegerField(
        _("ttl"), default=1440,
        help_text=_("""``Time to Live,`` the number of minutes a channel can be
        cached before refreshing."""))

    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="podcast_shows",
        verbose_name=_("owner"),
        help_text=_("""Make certain the user account has a name and e-mail address."""))

    editor_email = models.EmailField(
        _("editor email"), blank=True,
        help_text=_("Email address of the person responsible for the feed's content."))
    webmaster_email = models.EmailField(
        _("webmaster email"), blank=True,
        help_text=_("Email address of the person responsible for channel publishing."))

    if 'licenses' in settings.INSTALLED_APPS:
        license = models.ForeignKey(License, on_delete=models.CASCADE, verbose_name=_("license"))
    else:
        license = models.CharField(
            _("license"), max_length=255,
            help_text=_("To publish a podcast to iTunes it is required to set a license type."))

    organization = models.CharField(
        _("organization"), max_length=255,
        help_text=_("Name of the organization, company or Web site producing the podcast."))
    link = models.URLField(_("link"), help_text=_("""URL of either the main website or the
        podcast section of the main website."""))

    enable_comments = models.BooleanField(default=True)

    author_text = models.CharField(
        _("author text"), max_length=255, help_text=_("""
            This tag contains the name of the person or company that is most
            widely attributed to publishing the Podcast and will be
            displayed immediately underneath the title of the Podcast.
            The suggested format is: 'email@example.com (Full Name)'
            but 'Full Name' only, is acceptable. Multiple authors
            should be comma separated."""))

    title = models.CharField(_("title"), max_length=255)
    slug = AutoSlugField(_("slug"), populate_from="title", unique="True")

    subtitle = models.CharField(
        _("subtitle"), max_length=255,
        help_text=_("Looks best if only a few words, like a tagline."))

    # If the show is not on iTunes, many fields may be ignored in your user forms
    on_itunes = models.BooleanField(
        _("iTunes"), default=True,
        help_text=_("Checked if the podcast is submitted to iTunes"))

    description_pretty = models.TextField(
        _("pretty description"), blank=True,
        help_text="May be longer than 4000 characters and contain HTML tags and styling.")

    description = models.TextField(
        _("description"), max_length=4000, help_text=_("""
            This is your chance to tell potential subscribers all about your
            podcast. Describe your subject matter, media format,
            episode schedule, and other relevant info so that they
            know what they'll be getting when they subscribe. In
            addition, make a list of the most relevant search terms
            that you want yourp podcast to match, then build them into
            your description. Note that iTunes removes podcasts that
            include lists of irrelevant words in the itunes:summary,
            description, or itunes:keywords tags. This field can be up
            to 4000 characters."""))

    if 'photologue' in settings.INSTALLED_APPS:
        original_image = models.ForeignKey(Photo, on_delete=models.CASCADE, verbose_name=_("image"), default=None, null=True, blank=True, help_text=_("""
                A podcast must have 1400 x 1400 pixel cover art in JPG or PNG
                format using RGB color space. See our technical spec for
                details. To be eligible for featuring on iTunes Stores,
                choose an attractive, original, and square JPEG (.jpg) or
                PNG (.png) image at a size of 1400x1400 pixels. The image
                will be scaled down to 50x50 pixels at smallest in iTunes.
                For reference see the <a
                href="http://www.apple.com/itunes/podcasts/specs.html#metadata">iTunes
                Podcast specs</a>.<br /><br /> For episode artwork to
                display in iTunes, image must be <a
                href="http://answers.yahoo.com/question/index?qid=20080501164348AAjvBvQ">
                saved to file's <strong>metadata</strong></a> before
                enclosure uploading!"""))
    else:
        original_image = ImageField(
            _("image"), upload_to=get_show_upload_folder, blank=True, help_text=_("""
                A podcast must have 1400 x 1400 pixel cover art in JPG or PNG
                format using RGB color space. See our technical spec for
                details. To be eligible for featuring on iTunes Stores,
                choose an attractive, original, and square JPEG (.jpg) or
                PNG (.png) image at a size of 1400x1400 pixels. The image
                will be scaled down to 50x50 pixels at smallest in iTunes.
                For reference see the <a
                href="http://www.apple.com/itunes/podcasts/specs.html#metadata">iTunes
                Podcast specs</a>.<br /><br /> For episode artwork to
                display in iTunes, image must be <a
                href="http://answers.yahoo.com/question/index?qid=20080501164348AAjvBvQ">
                saved to file's <strong>metadata</strong></a> before
                enclosure uploading!"""))

    if ResizeToFill:
        admin_thumb_sm = ImageSpecField(source="original_image",
                                        processors=[ResizeToFill(50, 50)],
                                        options={"quality": 100})
        admin_thumb_lg = ImageSpecField(source="original_image",
                                        processors=[ResizeToFill(450, 450)],
                                        options={"quality": 100})
        img_show_sm = ImageSpecField(source="original_image",
                                     processors=[ResizeToFill(120, 120)],
                                     options={"quality": 100})
        img_show_lg = ImageSpecField(source="original_image",
                                     processors=[ResizeToFill(550, 550)],
                                     options={"quality": 100})
        img_itunes_sm = ImageSpecField(source="original_image",
                                       processors=[ResizeToFill(144, 144)],
                                       options={"quality": 100})
        img_itunes_lg = ImageSpecField(source="original_image",
                                       processors=[ResizeToFill(1400, 1400)],
                                       options={"quality": 100})

    feedburner = models.URLField(
        _("feedburner url"), blank=True,
        help_text=_("""Fill this out after saving this show and at least one
            episode. URL should look like "http://feeds.feedburner.com/TitleOfShow".
            See <a href="http://code.google.com/p/django-podcast/">documentation</a>
            for more. <a href="http://www.feedburner.com/fb/a/ping">Manually ping</a>"""))

    # iTunes specific fields
    explicit = models.PositiveSmallIntegerField(
        _("explicit"), default=1, choices=EXPLICIT_CHOICES,
        help_text=_("``Clean`` will put the clean iTunes graphic by it."))
    redirect = models.URLField(
        _("redirect"), blank=True,
        help_text=_("""The show's new URL feed if changing
            the URL of the current show feed. Must continue old feed for at least
            two weeks and write a 301 redirect for old feed."""))
    keywords = models.CharField(
        _("keywords"), max_length=255, blank=True,
        help_text=_("""A comma-demlimitedlist of up to 12 words for iTunes
            searches. Perhaps include misspellings of the title."""))
    itunes = models.URLField(
        _("itunes store url"), blank=True,
        help_text=_("""Fill this out after saving this show and at least one
            episode. URL should look like:
            "http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=000000000".
            See <a href="http://code.google.com/p/django-podcast/">documentation</a> for more."""))

    twitter_tweet_prefix = models.CharField(
        _("Twitter tweet prefix"), max_length=80,
        help_text=_("Enter a short ``tweet_text`` prefix for new episodes on this show."),
        blank=True)

    objects = ShowQuerySet.as_manager()
    tags = TaggableManager(blank=True)

    class Meta:
        verbose_name = _("Show")
        verbose_name_plural = _("Shows")
        ordering = ("organization", "slug")

    def __str__(self):
        return self.title

    def get_share_url(self):
        return "http://{0}{1}".format(Site.objects.get_current(), self.get_absolute_url())

    def get_absolute_url(self):
        return reverse("podcasting_show_detail", kwargs={"slug": self.slug})

    @property
    def current_episode(self):
        try:
            return self.episode_set.published().order_by("-published")[0]
        except IndexError:
            return None