【发布时间】:2021-12-29 16:51:43
【问题描述】:
使用 Django Pagination 我正在尝试使用 AJAX 进行无休止的分页。我按照这里的例子:https://www.progerhub.com/tutorial/adding-pagination-with-infinite-scroll-in-django/
我的视图可以很好地返回结果的第一页,但是当我尝试为其他页面构建内容并使用 render_to_string 将其作为 JSON 返回时,将数据附加到我的内容变量时出现错误。
错误信息
web_1 | Traceback (most recent call last):
...
web_1 | File "/usr/src/django/media/views.py", line 74, in get
web_1 | content += render_to_string('media_item.html', {'media': media, }, request=request)
...
web_1 | new_obj = func(obj, *arg_vals)
web_1 | File "/usr/local/lib/python3.8/site-packages/django/template/defaultfilters.py", line 784, in divisibleby
web_1 | return int(value) % int(arg) == 0
web_1 | TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
models.py
class Media(Audit):
def get_poster_path(instance, filename):
new_filename = "%s-%s" % (instance.sort_title, instance.year)
filename = "%s.jpg" % (slugify(new_filename))
upload_path = "posters/%s" % (filename)
return upload_path
imdb_id = models.CharField(
max_length=255,
blank=True,
null=True)
media_type = models.CharField(
max_length=16,
blank=False,
null=False,
choices=media_type_choices)
title = models.CharField(
max_length=255)
sort_title = models.CharField(
max_length=255,
blank=True,
null=True)
year = models.IntegerField(
blank=True,
null=True)
content_rating = models.CharField(
max_length=16,
blank=True,
null=True,
choices=media_content_rating_choices)
runtime = models.CharField(
max_length=16,
blank=True,
null=True)
release_date = models.DateField(
blank=True,
null=True)
genre_primary = models.ForeignKey(
Genre,
blank=True,
null=True,
on_delete=models.SET_NULL,
related_name='genre_primary')
genre_secondary = models.ForeignKey(
Genre,
blank=True,
null=True,
on_delete=models.SET_NULL,
related_name='genre_secondary')
quality = models.CharField(
max_length=16,
blank=True,
null=True,
choices=quality_choices)
language = models.CharField(
max_length=16,
blank=True,
null=True,
choices=language_choices)
description = models.CharField(
max_length=500,
blank=True,
null=True)
imdb_rating = models.DecimalField(
max_digits=3,
decimal_places=1,
blank=True,
null=True)
rotten_tomato_rating = models.IntegerField(
blank=True,
null=True)
metacritic_rating = models.IntegerField(
blank=True,
null=True)
download = models.BooleanField(
default=False,
help_text="Check this if media needs to be downloaded.")
fix = models.BooleanField(
default=False,
help_text="Check this if media needs to be fixed.")
notes = models.CharField(
max_length=500,
blank=True,
null=True)
omdb_date = models.DateField(
blank=True,
null=True)
poster = ProcessedImageField(
blank=True,
null=True,
format='JPEG',
options={'quality': 100},
processors=[ResizeToFill(1000, 1500)],
upload_to=get_poster_path)
class Meta:
ordering = (
'sort_title',
'title',
'year')
def __str__(self):
return self.title
views.py
class MediaView(LoginRequiredMixin, JsonMixin, View):
def get(self, request, *args, **kwargs):
context = self.get_context_data()
context['status_list'] = models.MediaStatus.objects.filter(user=self.request.user)
media = models.Media.objects.filter()
page = int(request.GET.get('page', 1))
p = paginator.Paginator(media, 24) # number of media per page
# try to get media for the given page
try:
media_page = p.page(page)
except paginator.EmptyPage:
media_page = paginator.Page([], page, p)
# get initial media list
if not request.is_ajax():
context['media_list'] = media_page
return render(request, 'media.html', context)
# get more media using ajax
else:
content = ''
for media in media_page:
content += render_to_string('media_item.html', {'media': media}, request=request)
data = {
'content': content,
'end_pagination': True if page >= p.num_pages else False,
}
print(data)
return self.render_to_json_response(data)
media_item.html
{% load static %}
{% load thumbnail %}
<div class="card media-item p-0 mb-4" onclick="parent.location='/media/{{ media.pk }}'">
{% if media.poster %}
{% thumbnail media.poster "400x600" crop="center" as thumb %}
<img class="w-100 img-fluid rounded" src="{{ thumb.url }}" width="{{ thumb.width }}" height="{{ thumb.height }}" onclick="parent.location='{{ media.poster.url }}'">
{% endthumbnail %}
{% else %}
<img class="w-100 media-poster img-fluid rounded" src="{% static 'images/no_poster.png' %}">
{% endif %}
<div class="media-overlay text-right pr-1">
<i class="fas fa-circle fa-2x pt-1 pr-0 d-none
{% for status in status_list %}
{% if status.media == media and status.watch == True %}
d-inline
{% elif status.media == media and status.watch == False %}
d-none
{% endif %}
{% endfor %}" style="color: #00bb8c;"></i>
<i class="fas fa-circle fa-2x pt-1 pr-0 {% if not media.download %}d-none{% endif %}" style="color: #e74c3c;"></i>
<i class="fas fa-circle fa-2x pt-1 pr-0 {% if not media.fix %}d-none{% endif %}" style="color: #f39c12;"></i>
</div>
<div class="card-header p-2">
{% if media.imdb_rating %}
<i class="fas fa-star" style="color: #efc63c;"></i> <span>{{ media.imdb_rating }}</span>
{% endif %}
{% if media.rotten_tomato_rating %}
<img src="
{% if media.rotten_tomato_rating > 60 %}
{% static 'images/icons/tomatometer.svg' %}
{% else %}
{% static 'images/icons/tomatometer_rotten.svg' %}
{% endif %}
" class="pl-3" style="margin: -3px 0 0 0; height: 18px;"> <span>{{ media.rotten_tomato_rating }}%</span>
{% endif %}
{% if media.metacritic_rating %}
<img src="{% static 'images/icons/metacritic.svg' %}" class="pl-3" style="margin: -3px 0 0 0; height: 18px;"> <span>{{ media.metacritic_rating }}</span>
{% endif %}
{% if not media.imdb_rating and not media.rotten_tomato_rating and not media.metacritic_rating %}
{% endif %}
</div>
<div class="card-body p-2">
<p class="card-title m-0 mb-2">
{{ media.title|truncatewords:10 }}
</p>
{% if media.content_rating %}
<p class="card-subtitle text-muted">
{{ media.content_rating }}
</p>
{% endif %}
</div>
</div>
<!-- wrap cards after certain number -->
{% if forloop.counter|divisibleby:2 %}<div class="w-100 d-none d-sm-block d-md-none"><!-- wrap every 3 on sm--></div>{% endif %}
{% if forloop.counter|divisibleby:2 %}<div class="w-100 d-none d-md-block d-lg-none"><!-- wrap every 4 on md--></div>{% endif %}
{% if forloop.counter|divisibleby:4 %}<div class="w-100 d-none d-lg-block d-xl-none"><!-- wrap every 5 on lg--></div>{% endif %}
{% if forloop.counter|divisibleby:6 %}<div class="w-100 d-none d-xl-block"><!-- wrap every 6 on xl--></div>{% endif %}
显然,我的render_to_string 中的{'media': media} 有问题,但我不确定是什么问题。这里有什么我忽略的吗?
【问题讨论】:
-
可以分享
media_item.html的内容吗,好像是模板出错了 -
我添加了完整的媒体模型和 media_item.html 的内容。
-
模板底部的所有
{% if forloop.counter|divisibleby:... %}是怎么回事?他们甚至不在 for 循环中 -
在
media.html模板中,media_item.html模板用于 for 循环。这似乎是破坏事物的原因。我将不得不重新考虑媒体项目的格式。