【问题标题】:Paginating Django View with Foreign Key Data使用外键数据对 Django 视图进行分页
【发布时间】:2021-12-20 22:17:59
【问题描述】:

我正在尝试构建一个简单的 Django 画廊,允许将照片添加到相册中。到目前为止一切正常(上传照片、添加到相册、对所有照片列表进行分页、照片详细信息/显示页面等),直到我尝试显示“相册”页面。我可以让页面呈现相册和所有相关照片,但如果我尝试对相册进行分页,事情就会变得很奇怪。

这是我的模型:

# models.py

class Albums(models.Model):
    id = models.AutoField(primary_key=True, unique=True)
    name = models.CharField(max_length=500)
    slug = models.SlugField(max_length=500, unique=True)
    description = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        return super().save(*args, **kwargs)


class Photos(models.Model):    
    id = models.AutoField(primary_key=True, unique=True)
    album = models.ForeignKey(
        Albums, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Album"
    )
    photo = models.ImageField(upload_to="photos/")
    slug = models.CharField(max_length=16, null=False, editable=False) # I know I'm not using a SlugField here; that's on purpose
    title = models.CharField(max_length=500)
    description = models.TextField(blank=True, null=True)
    upload_date = models.DateTimeField(
        default=timezone.now, verbose_name="Date uploaded"
    )
    
    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        [...] # stuff to get the image's EXIF data and use that to set the slug
        self.slug = str(datetime.strftime(img_date, "%Y%m%d%H%M%S"))
        [...] # plus a bunch of other stuff that happens on save, not important here
        super(Photos, self).save()

    def delete(self, *args, **kwargs):
        [...] # a bunch of stuff that happens on delete, not important here
        super(Photos, self).delete()

还有让我痛苦的观点:

# views.py

class PhotoAlbum(DetailView):
    context_object_name = "album"
    model = Albums
    slug_field = "slug"
    template_name = "page.html"

    def get_photos(self, **kwargs):
        # get the integer id of the album
        a = Albums.objects.filter(slug=self.kwargs["slug"])
        a_id = a.values()[0]["id"]
        # get the list go photos in that album
        photos = Photos.objects.all().order_by("-capture_date").filter(album_id=a_id)
        return photos

    def get_context_data(self, **kwargs):
        context = super(PhotoAlbum, self).get_context_data(**kwargs)
        context["photos"] = self.get_photos()
        return context

这些在基本模板中工作...

# album.html
<h2>{{ album.name }}</h2>
<p>{{ album.description }}</p>
<ul>
    {% for photo in photos %}
        <li><a href="{% url 'photo_detail' photo.slug %}">{{ photo.title }}</a></li>
    {% endfor %}
</ul>

...但是如果我尝试通过更改对照片进行分页...

photos = Photos.objects.all().order_by("-capture_date").filter(album_id=a_id)

...到...

photos = Paginator(Photos.objects.all().order_by("-capture_date").filter(album_id=a_id), 10)

...我什么也得不到。

在四处搜索时,我看到的几乎所有与分页有关的问题都是针对 DRF 的,所以在这里碰壁了。我在显示照片与相册的关系时遇到了各种麻烦(get_photos() 函数),所以我猜测我的部分问题在于。有关如何使其正常工作的任何建议?

【问题讨论】:

    标签: django django-models django-views django-orm django-pagination


    【解决方案1】:

    Paginator 会给你一个分页器对象,而不是你正在分页的对象。要获取对象,首先需要指定页面,例如:

    paginator = Paginator(Photos.objects.all().order_by("-capture_date").filter(album_id=a_id), 10)
    photos = paginator.page(1)
    

    photos 此处将包含 Photos 第 1 页上的对象。

    【讨论】:

    • 谢谢!这确实回答了我的问题,但提出了另一个问题;有没有办法在我的模板标签中使用 is_paginated 并在我的模板中获取 page_obj.paginator.num_pagespage_obj.previous_page_number 值,就像我使用内置的 paginate_by 一样?
    • 是的,但您必须构建模板来支持它,类似于ListView 所做的。也许您可以使用 ListView 来代替按相册 ID 过滤的照片列表?
    • 当然……我完全忘记了我使用的是 DetailView。再次感谢!
    【解决方案2】:

    基于Brian Desturacomment,我返回并使用ListView 重新开始,在re-reading the Django docs 和一些混乱之后,我的观点得出了这个解决方案,基于一点测试,对我有用:

    class AlbumDetail(ListView):
        context_object_name = "photos"
        template_name = "page.html"
        paginate_by = 6
    
        def get_queryset(self):
            a = Albums.objects.filter(slug=self.kwargs["slug"])
            a_id = a.values()[0]["id"]
            self.albums = get_object_or_404(Albums, slug=self.kwargs["slug"])
            return Photos.objects.filter(album_id=a_id).order_by("-capture_date")
    
        def get_context_data(self, **kwargs):
            context = super(AlbumDetail, self).get_context_data(**kwargs)
            context["album"] = self.albums
            return context
    

    【讨论】:

      【解决方案3】:

      viwes.py

      class PhotoAlbum(ListView):
          context_object_name = "album"
          model = Albums
          slug_field = "slug"
          template_name = "page.html"
          paginate_by = 5
      

      page.html

      这是分页逻辑

      {%if is_paginated %}
      
               {%if page_obj.has_previous %}
                <a style="margin-left: 20px; padding: 10px 20px;" class=" btn btn-primary" href="?page={{page_obj.previous_page_number}}"> ?{{page_obj.num_pages}} previous</a>
                
               {% endif %}
      
               {%if page_obj.has_next %}
               {% if page_obj.num_pages == 1 %}
                   <a style="margin-left: 930px; padding: 10px 28px;" class=" btn btn-primary" href="?page={{page_obj.next_page_number}}">next ?</a>
                {% else %}
                  <a style="margin-left: 880px; padding: 10px 28px;" class=" btn btn-primary" href="?page={{page_obj.next_page_number}}">next ?</a>
                 {% endif %}
               {% endif %}
      
             {% endif %} 
      

      【讨论】:

      • 这给了我一个基本的相册列表(我已经有了),但我想做的是获取一个给定相册in的照片列表,基于关于我原始问题中模型中概述的外键关系。我在上面发布的answer 就是这样做的。
      猜你喜欢
      • 2019-03-23
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 2016-12-09
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多