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

Django Rest Framework:如何通过分类名称而非ID创建新产品

问题描述

在Django中创建了Category和Product两个模型,通过React前端用Axios发起POST请求创建产品时,只能通过分类ID提交成功,无法使用分类名称(硬编码或下拉选择都不行),Postman测试结果一致。期望提交参数格式为:

{
  "name": "Coca Cola",
  "category": "Beverage"
}

而非当前仅能生效的格式:

{
  "name": "Coca Cola",
  "category": 1
}

现有代码

模型代码(models.py)

class Category(models.Model):
    name = models.CharField(max_length=50)
    slug = models.SlugField(unique=True, null=True, blank=True)
    
    def save(self,*args, **kwargs):
        self.slug = slugify(self.name)
        super(Category, self).save(*args, **kwargs)

    def __str__(self):
        return self.name


class Product(models.Model):
    upc = models.CharField(max_length=30)
    name = models.CharField(max_length=100)
    description = models.TextField(max_length=255)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
    quantity = models.IntegerField()
    price = models.IntegerField()

    def __str__(self):
        return self.name

视图代码(views.py)

from .models import Product
from .serializers import ProductSerializers
from rest_framework import generics


class ProductList(generics.ListCreateAPIView):
    serializer_class = ProductSerializers

    def get_queryset(self):
        queryset = Product.objects.all()

        return queryset

class ProductDetail(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = ProductSerializers
    queryset = Product.objects.all()

序列化器代码(serializers.py)

from .models import Product, Category
from rest_framework import serializers


class CategorySerializers(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields="__all__"

class ProductSerializers(serializers.ModelSerializer):
    category_name = serializers.SerializerMethodField('get_category_name')
    
    def get_category_name(self, obj):
        if obj.category_id:
            return obj.category.name

    class Meta:
        model = Product
        fields = '__all__'
解决方案

当前的ProductSerializers只处理了返回数据时的分类名称(category_name字段),但完全没处理创建/更新产品时接收分类名称并映射到对应Category实例的逻辑。下面提供两种可行方案:

方案一:使用SlugRelatedField(推荐)

直接修改Product序列化器,把默认的category字段替换为SlugRelatedField,指定用分类的name字段来匹配:

from .models import Product, Category
from rest_framework import serializers

class CategorySerializers(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = "__all__"

class ProductSerializers(serializers.ModelSerializer):
    category = serializers.SlugRelatedField(
        queryset=Category.objects.all(),
        slug_field='name'  # 明确用分类名称作为匹配依据
    )
    category_name = serializers.SerializerMethodField('get_category_name')
    
    def get_category_name(self, obj):
        if obj.category_id:
            return obj.category.name

    class Meta:
        model = Product
        fields = '__all__'
  • 改完之后,提交请求时直接传category: "Beverage",序列化器会自动查找名称为Beverage的Category实例,关联到新创建的Product上。
  • 如果提交的分类名称不存在,会返回序列化验证错误,符合接口规范。

方案二:自定义创建逻辑(支持自动创建分类)

如果需要实现「提交的分类名称不存在时自动创建分类」的功能,可以重写序列化器的create方法:

class ProductSerializers(serializers.ModelSerializer):
    category_name = serializers.SerializerMethodField('get_category_name')
    # 将category字段设为仅写入,接收分类名称
    category = serializers.CharField(write_only=True)
    
    def get_category_name(self, obj):
        if obj.category_id:
            return obj.category.name

    def create(self, validated_data):
        # 从验证数据中取出分类名称
        category_name = validated_data.pop('category')
        # 查找分类,不存在则创建(get_or_create返回实例和是否创建的布尔值)
        category, _ = Category.objects.get_or_create(name=category_name)
        # 把分类实例放回验证数据,创建产品
        validated_data['category'] = category
        return super().create(validated_data)

    class Meta:
        model = Product
        fields = '__all__'
  • 这种方式下,不管分类是否存在,都能成功创建关联对应分类的产品。
  • write_only=True确保返回产品数据时,不会把分类名称返回到category字段(如果需要返回分类名称,保留category_name字段即可)。

测试验证

修改完成后,用Postman或React前端发送如下请求:

{
  "upc": "123456",
  "name": "Coca Cola",
  "description": "碳酸饮料",
  "category": "Beverage",
  "quantity": 100,
  "price": 3
}

即可成功创建关联指定分类的产品。

内容的提问来源于stack exchange,提问作者Ajay GC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 17:46:15