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

Django MPTT如何生成含父级标题的完整名称?DRF实现问询

在Django MPTT中自动生成完整名称(full_name)的实现方案

当然可以轻松实现!针对你的RecipeCategory模型,我会从模型自动保存full_name和Django REST Framework序列化两个层面给你具体方案,完全适配你的需求。

一、模型层面自动生成并保存full_name

你可以通过重写模型的save()方法,在保存或更新分类时自动计算full_name的值。根据你的需求(格式为「标题 - 父级标题」),代码实现如下:

from mptt.models import MPTTModel, TreeForeignKey
from django.db import models
from django.contrib.auth.models import User
from autoslug import AutoSlugField

class RecipeCategory(MPTTModel):
    title = models.CharField(max_length=255, verbose_name='Nazwa kategorii')
    full_name = models.CharField(max_length=255, verbose_name='Pełna nazwa')
    body = models.TextField(verbose_name='Opis kategorii', blank=True, help_text='To pole nie jest obowiązkowe. Jeśli chcesz, możesz napisać co konkretnie ma być dodawane do tej kategorii.')
    image = models.ImageField(upload_to='Tło', default='defaultbgcategory.jpg' ,verbose_name='Tło kategorii', help_text='Dodając zdjęcie jesteś w stanie wyróżnić kategorię, jeśli jednak tego nie zrobisz nic się nie stanie. :)', null=True, blank=True)
    slug = AutoSlugField(populate_from='title', unique=True)
    parent = TreeForeignKey('self', related_name='children', db_index=True, on_delete=models.CASCADE, null=True, blank=True, verbose_name='Kategoria')
    subscribers = models.ManyToManyField(User, related_name='subscribed_category', blank=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)

    def save(self, *args, **kwargs):
        # 计算full_name:如果有父级则拼接,否则直接用自身title
        if self.parent:
            self.full_name = f"{self.title} - {self.parent.title}"
            # 扩展:如果需要多级完整路径(比如「爷爷分类 - 父分类 - 当前分类」),可以用下面的代码替换上面一行
            # ancestors = self.get_ancestors(ascending=False, include_self=False)
            # title_chain = [ancestor.title for ancestor in ancestors] + [self.title]
            # self.full_name = " - ".join(title_chain)
        else:
            self.full_name = self.title
        # 调用父类的save方法完成保存
        super().save(*args, **kwargs)

补充:父级标题更新时同步子级full_name

如果父分类的title修改了,子分类的full_name不会自动更新。你可以通过信号来解决这个问题,当父分类保存后,自动更新所有子分类的full_name:

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=RecipeCategory)
def update_child_full_names(sender, instance, **kwargs):
    # 遍历当前分类的所有子分类,触发它们的save方法重新计算full_name
    for child in instance.children.all():
        child.save()

二、Django REST Framework中的处理

在DRF中,你有两种方式返回full_name,可以根据需求选择:

方式1:直接序列化数据库中已保存的full_name

这种方式最简单,直接在序列化器中包含full_name字段即可:

from rest_framework import serializers
from .models import RecipeCategory

class RecipeCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = RecipeCategory
        # 列出你需要返回的字段,包含full_name
        fields = ['id', 'title', 'full_name', 'parent', 'slug', 'body']

方式2:动态计算full_name(不依赖数据库字段)

如果你不想把full_name存在数据库里,或者需要实时计算最新值,可以用SerializerMethodField动态生成:

from rest_framework import serializers
from .models import RecipeCategory

class RecipeCategorySerializer(serializers.ModelSerializer):
    # 定义动态字段
    full_name = serializers.SerializerMethodField()

    def get_full_name(self, obj):
        # 逻辑和模型save方法里的一致
        if obj.parent:
            return f"{obj.title} - {obj.parent.title}"
        return obj.title

    class Meta:
        model = RecipeCategory
        fields = ['id', 'title', 'full_name', 'parent', 'slug', 'body']

这样无论你是在后台管理中操作,还是通过DRF接口访问,都能得到符合要求的full_name啦!

内容的提问来源于stack exchange,提问作者Maciej Urmański

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 11:27:28