You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django Admin中将两个同字段模型合并为一个并实现一对多关系

合并Django模型并实现父子层级关系方案

一、重构模型(自关联外键实现父子关系)

将两个字段重复的模型合并为一个,通过自关联外键实现一对多的父子层级,代码如下:

from django.db import models

class AnimalGroup(models.Model):
    name = models.CharField(max_length=50, unique=True)    
    description = models.TextField(max_length=1000, blank=True)
    images = models.ImageField(upload_to="photos/groups")
    # 自关联外键,实现父子关系
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,  # 父组删除时子组同步删除,可按需改为PROTECT防止误删
        null=True,
        blank=True,
        related_name='subgroups'  # 父组通过该属性快速获取所有子组
    )

    def __str__(self):
        return self.name

二、配置Django Admin优化操作体验

在Admin后台实现直观的父子组创建、关联功能,同时优化列表展示的层级可读性:

from django.contrib import admin
from .models import AnimalGroup

class AnimalGroupAdmin(admin.ModelAdmin):
    # 列表显示字段
    list_display = ('get_name_with_indent', 'parent', 'description')
    # 搜索功能
    search_fields = ('name', 'description')

    # 限制父组选择范围(仅显示顶级组,避免循环关联)
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'parent':
            kwargs['queryset'] = AnimalGroup.objects.filter(parent__isnull=True)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

    # 列表中显示层级缩进,直观区分父子组
    def get_name_with_indent(self, obj):
        indent = ''
        current_parent = obj.parent
        while current_parent:
            indent += '---'
            current_parent = current_parent.parent
        return f'{indent}{obj.name}'
    get_name_with_indent.short_description = '组名称'

admin.site.register(AnimalGroup, AnimalGroupAdmin)

三、数据迁移(从旧模型同步数据)

如果已有旧模型数据,需编写自定义迁移脚本将数据同步到新模型:

  1. 先生成新模型的迁移文件并执行:
python manage.py makemigrations
python manage.py migrate
  1. 创建自定义迁移脚本(替换yourapp为你的应用名):
from django.db import migrations

def migrate_old_data(apps, schema_editor):
    # 取出旧模型类
    OldAnimalGroup = apps.get_model('yourapp', 'AnimalGroup')
    OldAnimalSubGroup = apps.get_model('yourapp', 'AnimalSubGroup')
    # 取出新模型类
    NewAnimalGroup = apps.get_model('yourapp', 'AnimalGroup')

    # 迁移旧父组数据(无父级)
    for old_group in OldAnimalGroup.objects.all():
        NewAnimalGroup.objects.create(
            name=old_group.name,
            description=old_group.description,
            images=old_group.images,
            parent=None
        )

    # 迁移旧子组数据并关联对应父组(假设旧子组通过`group`字段关联旧父组)
    for old_subgroup in OldAnimalSubGroup.objects.all():
        parent_group = NewAnimalGroup.objects.get(name=old_subgroup.group.name)
        NewAnimalGroup.objects.create(
            name=old_subgroup.name,
            description=old_subgroup.description,
            images=old_subgroup.images,
            parent=parent_group
        )

class Migration(migrations.Migration):
    dependencies = [
        ('yourapp', '0003_animalgroup'),  # 替换为新模型迁移文件的编号
    ]

    operations = [
        migrations.RunPython(migrate_old_data),
    ]
  1. 执行迁移脚本完成数据同步:
python manage.py migrate

四、使用方式

  • 创建父组:在Admin后台新增AnimalGroup时,parent字段留空即可(如mammals、fish)。
  • 创建子组:新增时在parent下拉框选择对应的父组(如bigCat关联mammals)。

内容的提问来源于stack exchange,提问作者mightycode Newton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:55:19