Django中父模型ListView视图能否访问子模型字段?
问题:Django继承模型在ListView中能否访问子类字段?
我创建了productForArt和albomForArt模型,其中albomForArt继承自productForArt。基于generic.ListView创建视图并在模板中输出数据,请问能否在模板中访问albomForArt模型的numberOfPages字段?或者此时Django返回的是带有albomForArt属性的albomForArt对象吗?
模型代码
from django.db import models class productForArt(models.Model): class Meta: verbose_name = u'товар' # 商品 verbose_name_plural = u'товары' # 商品(复数) price = models.IntegerField(verbose_name="цена", default=0) # 价格 title = models.CharField(max_length=300, verbose_name="название товара", null=True) # 商品名称 description = models.CharField(max_length=1000, verbose_name="Описание товара", null=True) # 商品描述 type = models.ForeignKey('typeProductForArt', on_delete=models.PROTECT) def getType(self): return self.type def __str__(self): return str(self.title) + ' по цене' + str(self.price) + ' шт' # 名称 + 价格 + 件 class albomForArt(productForArt): numberOfPages = models.IntegerField(default=10, verbose_name="количество станиц") # 页数 class typeProductForArt(models.Model): title = models.CharField(max_length=200, default="none") def __str__(self): return self.title
视图代码
from django.views import View, generic from .models import productForArt class startPage(generic.ListView): model = productForArt template_name = "startPage.html" context_object_name = "productForArt_list" queryset = productForArt.objects.all()[:20]
模板代码
{% if productForArt_list %} <section class="productsStartpage"> {% for productForArt in object_list %} <article class="productForArtStartpage"> <h1>{{productForArt.title}}</h1> <p>{{productForArt.description}}</p> </article> {% endfor %} </section> {% else %} <p>товара нету</p> <!-- 没有商品 --> {% endif %}
回答
关于返回的对象
你当前的ListView查询productForArt.objects.all()会返回所有productForArt及其子类albomForArt的实例,但默认是以父类productForArt的形式返回。不过Django会自动为子类实例添加一个小写类名的关联属性(比如albomforart),通过这个属性可以访问子类的专属字段。
模板中访问numberOfPages的方法
直接写{{ productForArt.numberOfPages }}会报错(非albomForArt实例没有该字段),可以用以下几种方式处理:
1. 自定义模板标签判断类型
在app下创建templatetags/product_tags.py:
from django import template from ..models import albomForArt register = template.Library() @register.filter def is_albom(obj): return isinstance(obj, albomForArt)
模板中加载标签后使用:
{% load product_tags %} {% for product in productForArt_list %} <article class="productForArtStartpage"> <h1>{{ product.title }}</h1> <p>{{ product.description }}</p> {% if product|is_albom %} <p>页数:{{ product.albomforart.numberOfPages }}</p> {% endif %} </article> {% endfor %}
2. 利用模板容错性处理
Django模板会忽略不存在的属性,结合default过滤器避免显示空值:
{% for product in productForArt_list %} <article class="productForArtStartpage"> <h1>{{ product.title }}</h1> <p>{{ product.description }}</p> <p>页数:{{ product.albomforart.numberOfPages|default:"无" }}</p> </article> {% endfor %}
3. 使用多态查询优化(推荐)
安装django-polymorphic库(pip install django-polymorphic),并将其加入INSTALLED_APPS,然后修改查询集:
# views.py queryset = productForArt.objects.all().select_subclasses()[:20]
此时查询返回的是实际子类的实例,模板中可直接判断并访问:
{% load product_tags %} {% for product in productForArt_list %} <article class="productForArtStartpage"> <h1>{{ product.title }}</h1> <p>{{ product.description }}</p> {% if product|is_albom %} <p>页数:{{ product.numberOfPages }}</p> {% endif %} </article> {% endfor %}
关键结论
- Django返回的父类查询结果中,子类实例会携带对应的子类属性,可通过
小写类名关联属性访问; - 必须先判断对象是否为子类实例,再访问专属字段,避免模板报错。
内容的提问来源于stack exchange,提问作者Камил Нарыгин
相关产品推荐
相关产品推荐

