Я работаю над проектом, используя следующие компоненты:
django: v2.2.10
django -подкастинг: 1.3.2
django -imagekit: 4.0.2
django -фотолог: 3.11
Когда я пытаюсь добавить новое подкаст-шоу, я получаю следующее сообщение об ошибке:
AttributeError at / admin / podcasting / 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
imagekit / cachefiles / init .py
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)
фотолог / models.py
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
/ path / to / django -подкастинг / Podcasting / models.py
@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
Я могу выполнять функции CRUD приложения-фотолога в администраторе - так что этот факт (в сочетании с трассировкой стека, когда в приложении imagekit создается первое исключение), заставляет меня поверить, что ошибка вызвана исключительно кодом генерации имени кэша в imagekit.
Однако я потратил более нескольких часов, пытаясь точно определить причину ошибки, но не могу найти съел это. Это известная ошибка с django -imagekit или я что-то упустил?
Как я могу исправить эту ошибку?