如何在Django中将两个模型合并,在Admin面板单表展示全部信息?
在Django Admin中用单个表格展示两个模型的信息
当然可以,不用Inline也能实现,根据你想以哪个模型为核心展示,有两种常用方案:
方案一:以用户为核心,展示用户+默认地址信息
如果希望每一行是一个用户,同时显示其默认地址的详情,可以自定义UserAdmin,通过关联查询获取地址字段:
from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from .models import User, Address class CustomUserAdmin(BaseUserAdmin): # 定义表格要显示的所有字段(用户字段+默认地址字段) list_display = ( 'email', 'first_name', 'last_name', 'phone', 'company_name', 'gst_no', 'default_street', 'default_apartment', 'default_country', 'default_state', 'default_city', 'default_zip', 'default_address_type' ) # 预取关联地址,避免N+1查询优化性能 def get_queryset(self, request): return super().get_queryset(request).prefetch_related('address') # 自定义方法获取默认地址的街道信息 def default_street(self, obj): default_addr = obj.address.filter(default=True).first() return default_addr.street_address if default_addr else '-' default_street.short_description = '街道地址' # 自定义方法获取默认地址的公寓信息 def default_apartment(self, obj): default_addr = obj.address.filter(default=True).first() return default_addr.apartment_address if default_addr else '-' default_apartment.short_description = '公寓地址' # 依次为其他地址字段添加类似方法 def default_country(self, obj): default_addr = obj.address.filter(default=True).first() return default_addr.country.name if default_addr else '-' default_country.short_description = '国家' def default_state(self, obj): default_addr = obj.address.filter(default=True).first() return default_addr.state if default_addr else '-' default_state.short_description = '省份' def default_city(self, obj): default_addr = obj.address.filter(default=True).first() return default_addr.city if default_addr else '-' default_city.short_description = '城市' def default_zip(self, obj): default_addr = obj.address.filter(default=True).first() return default_addr.zip if default_addr else '-' default_zip.short_description = '邮编' def default_address_type(self, obj): default_addr = obj.address.filter(default=True).first() return dict(Address.ADDRESS_CHOICES).get(default_addr.address_type, '-') if default_addr else '-' default_address_type.short_description = '地址类型' admin.site.register(User, CustomUserAdmin)
这个方案会把每个用户的默认地址信息和用户自身字段放在同一行表格里,没有默认地址的用户会显示-占位。
方案二:以地址为核心,展示地址+所属用户信息
如果希望每一行是一个地址,同时显示该地址对应的用户全量信息,可以自定义AddressAdmin,关联获取用户字段:
from django.contrib import admin from .models import Address class AddressAdmin(admin.ModelAdmin): list_display = ( 'user_email', 'user_first_name', 'user_last_name', 'user_phone', 'user_company_name', 'user_gst_no', 'street_address', 'apartment_address', 'country', 'state', 'city', 'zip', 'address_type', 'default' ) # 预取关联用户,优化查询性能 def get_queryset(self, request): return super().get_queryset(request).select_related('user') # 自定义方法获取用户邮箱 def user_email(self, obj): return obj.user.email user_email.short_description = '用户邮箱' # 自定义方法获取用户名字 def user_first_name(self, obj): return obj.user.first_name user_first_name.short_description = '名字' # 依次为其他用户字段添加类似方法 def user_last_name(self, obj): return obj.user.last_name user_last_name.short_description = '姓氏' def user_phone(self, obj): return obj.user.phone user_phone.short_description = '手机号' def user_company_name(self, obj): return obj.user.company_name or '-' user_company_name.short_description = '公司名称' def user_gst_no(self, obj): return obj.user.gst_no or '-' user_gst_no.short_description = 'GST编号' admin.site.register(Address, AddressAdmin)
这个方案每一行对应一个地址,同时展示所属用户的所有信息,适合需要查看地址关联用户详情的场景。
补充:处理多地址场景
如果想在用户行里展示所有关联地址(而不只是默认地址),可以把地址字段用逗号拼接展示,比如:
def all_addresses(self, obj): return ', '.join([f"{addr.street_address}({addr.address_type})" for addr in obj.address.all()]) all_addresses.short_description = '所有地址'
把这个方法加入list_display即可,不过这种方式在地址较多时表格会显得拥挤,按需使用即可。
内容的提问来源于stack exchange,提问作者Sins97
相关产品推荐
相关产品推荐

