Django:如何从一对一关联的两个模型取数生成指定表格?
Django 跨模型数据表格实现方案
一、模型是否需要修改?
现有模型仅需修正一处笔误,无需调整关联结构:
Car模型中car_exterior_color字段多写了一个等号,修正后补充必要参数和示例选项;CarWash的wash_date需设置允许空值,适配未洗车车辆的无日期场景。
修正后的完整模型代码:
from django.db import models class Car(models.Model): model_name = models.CharField(max_length=100) make_name = models.CharField(max_length=100) # 定义颜色选项示例,可根据需求扩展 COLOR_CHOICES = [ ('blue', 'Blue'), ('white', 'White'), ('red', 'Red'), ('green', 'Green'), ('yellow', 'Yellow'), ('black', 'Black') ] car_exterior_color = models.CharField(max_length=20, choices=COLOR_CHOICES) class CarWash(models.Model): car_washed = models.BooleanField(default=False) wash_date = models.DateTimeField(null=True, blank=True) added_wax = models.BooleanField(default=False) car = models.OneToOneField(Car, on_delete=models.CASCADE, verbose_name="Car washed")
二、视图层代码实现(views.py)
采用函数视图直观实现,通过select_related预加载关联数据避免N+1查询,同时整理表格所需格式化数据:
from django.shortcuts import render from .models import Car def car_wash_table(request): # 预加载关联的CarWash数据,提升查询性能 cars = Car.objects.select_related('carwash').all() table_data = [] for car in cars: # 处理无洗车记录的情况,避免属性报错 wash_record = getattr(car, 'carwash', None) table_data.append({ 'model_name': car.model_name, 'make_name': car.make_name, # 若使用choices,用get_xxx_display()显示友好名称,否则直接取字段值 'car_ext_col': car.get_car_exterior_color_display(), 'car_washed': 'Yes' if (wash_record and wash_record.car_washed) else 'No', 'added_wax': 'Yes' if (wash_record and wash_record.added_wax) else 'No', 'wash_date': wash_record.wash_date.strftime('%Y-%m-%d') if (wash_record and wash_record.wash_date) else '--' }) return render(request, 'car_wash_table.html', {'table_data': table_data})
如果偏好类视图(ListView),可参考以下实现:
from django.views.generic import ListView from .models import Car class CarWashTableView(ListView): model = Car template_name = 'car_wash_table.html' def get_queryset(self): return Car.objects.select_related('carwash').all() def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) table_data = [] for car in context['object_list']: wash_record = getattr(car, 'carwash', None) table_data.append({ 'model_name': car.model_name, 'make_name': car.make_name, 'car_ext_col': car.get_car_exterior_color_display(), 'car_washed': 'Yes' if (wash_record and wash_record.car_washed) else 'No', 'added_wax': 'Yes' if (wash_record and wash_record.added_wax) else 'No', 'wash_date': wash_record.wash_date.strftime('%Y-%m-%d') if (wash_record and wash_record.wash_date) else '--' }) context['table_data'] = table_data return context
三、模板层渲染(car_wash_table.html)
直接使用视图传递的格式化数据生成表格:
<div class="s-table-container"> <table class="s-table"> <thead> <tr> <th>model_name</th> <th>make_name</th> <th>car_ext_col</th> <th>car_washed ?</th> <th>added_wax ?</th> <th>wash date</th> </tr> </thead> <tbody> {% for item in table_data %} <tr> <td>{{ item.model_name }}</td> <td>{{ item.make_name }}</td> <td>{{ item.car_ext_col }}</td> <td>{{ item.car_washed }}</td> <td>{{ item.added_wax }}</td> <td>{{ item.wash_date }}</td> </tr> {% endfor %} </tbody> </table> </div>
四、关键注意事项
- 反向关联名称:若
CarWash的OneToOneField设置了related_name,需将select_related('carwash')替换为对应的名称; - 空值处理:必须通过
getattr判断洗车记录是否存在,避免无关联记录时抛出AttributeError; - 性能优化:
select_related适用于一对一/外键关联,能将两次查询合并为一次,显著提升数据加载效率。
内容的提问来源于stack exchange,提问作者PrertoQuebas
相关产品推荐
相关产品推荐

