Django 2.1中如何通过关联模型在模板获取字段值?
首先看你当前模板里的核心问题:{{album.image_set.model.low}} 是错误写法——image_set 是当前Album关联的所有Image对象的集合,而 .model 指向的是Image模型类而非具体实例,自然拿不到low字段的值。下面给你几个无需大幅重构代码的解决办法:
方法一:模板直接取随机图(改动最小)
利用Django内置的random模板过滤器,直接从每个相册的关联图片集合里随机选一张,再获取它的low字段。同时要处理相册无图片的情况,避免报错:
<div class="item2 my-gallery responsive" itemscope itemtype="http://schema.org/ImageGallery"> {% for album in albums %} <div class="gallery"> <a href="/albums/{{ album.id }}"> {% if album.image_set.exists %} <img src="{{ album.image_set.all|random }}.low" width="300" height="225"> {% else %} <!-- 可替换为你的默认占位图路径 --> <img src="/static/images/no-image-placeholder.jpg" width="300" height="225"> {% endif %} </a> <div class="desc">{{album}}</div> </div> {% endfor %} </div>
这个方案几乎不用修改后端代码,只调整模板即可,完全符合你不想大幅重构的需求。
方法二:后端优化查询(减少数据库请求)
如果相册和图片数量较多,模板中每个相册单独查一次图片集合会出现N+1查询的性能问题。这时只需在views.py里给查询集加上prefetch_related预取关联数据,模板写法和方法一保持一致:
修改views.py中的albums_list定义:
albums_list = Album.objects.all().prefetch_related('image_set')
这样Django会一次性拉取所有相册及其关联的图片,大幅减少数据库请求次数,改动同样很小。
关于你尝试的「相册随机预览图」问题
你之前在views.py里取的是所有Image中的随机一张,而非对应相册的图片,所以达不到预期效果。上面的两个方法已经解决了每个相册显示自身随机预览图的需求。如果你更倾向于在后端给每个相册绑定随机图,也可以这么做:
在views.py的albums函数中,遍历相册列表并添加自定义属性:
def albums(request): albums_list = Album.objects.all().prefetch_related('image_set') # 给每个相册绑定随机图片属性 for album in albums_list: images = album.image_set.all() album.random_image = images[random.randint(0, len(images)-1)] if images else None paginator = Paginator(albums_list, 20) page = request.GET.get('page') albums = paginator.get_page(page) context = { 'albums': albums, } return render(request, 'gallery/albums.html', context)
然后模板中可以这样调用:
{% if album.random_image %} <img src="{{ album.random_image.low }}" width="300" height="225"> {% else %} <img src="/static/images/no-image-placeholder.jpg" width="300" height="225"> {% endif %}
这个改动仅在后端多了一步遍历赋值,同样属于小范围调整。
另外补充个小细节:如果需要全局随机取一张Image,建议用Image.objects.order_by('?').first()替代Image.objects.all()[random_idx],后者在图片数量变化时容易出现索引越界问题。
内容的提问来源于stack exchange,提问作者Vjerc

