跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于 Django drf 的反序列化一对多字段问题
未分類
13 4 月 2021

关于 Django drf 的反序列化一对多字段问题

关于 Django drf 的反序列化一对多字段问题

資深大佬 : endpain 5

大家好,我在使用 django drf 的时候遇到了一个问题,找了一堆资料,暂时还没找到好的解决方法,希望有懂的兄弟可以给指点一下。非常感谢。

models.py

 class ProjectStatusModels(models.Model):     name = models.CharField(max_length=150,verbose_name='状态名称',unique=True,db_index=True)      def __str__(self):         return self.name     class Meta:         verbose_name = '项目状态管理表'         ordering = ('-id',)   class ProjectModels(models.Model):     project_id = models.CharField(verbose_name='项目编号',max_length=120,unique=True,db_index=True)     name = models.CharField(verbose_name='项目名称',max_length=150)     customer_name = models.CharField(verbose_name='客户名称',max_length=150,null=True,blank=True)     evaluation = models.IntegerField(verbose_name='项目估价',null=True,blank=True)      start_date = models.DateField(verbose_name='项目开始日期',null=True,blank=True)     expiration_date = models.DateField(verbose_name='项目截止日期',null=True,blank=True)      sales_name = models.ForeignKey(EmployeeModels,on_delete=models.DO_NOTHING,verbose_name='销售经理',null=True,blank=True)     status = models.ForeignKey(ProjectStatusModels,on_delete=models.DO_NOTHING,verbose_name='状态',null=True,blank=True,db_index=True)      create_time = models.DateTimeField(verbose_name='发布时间', auto_now_add=True)     update_time = models.DateTimeField(verbose_name='修改时间', auto_now=True)      def __str__(self):         return self.name     class Meta:         verbose_name = '项目管理表'         ordering = ('-id',)  

view.py

class ProjectJsonView(APIView):     def get(self,request,*args,**kwargs):         project_id = request.query_params.get('project_id')         if not project_id:             project_obj = project_models.ProjectModels.objects.all()             ser = admin_project_serializers.ProjectModelsSerializers(instance=project_obj,many=True)         else:             project_obj = project_models.ProjectModels.objects.filter(id=project_id).first()             ser = admin_project_serializers.ProjectModelsSerializers(instance=project_obj,many=False)          return Response({             'status_code':20000,             'code':0,             'data':ser.data         })      def post(self,request,*args,**kwargs):         # 新增项目         req = {             'status_code':20000,             'msg':'新增成功'         }         ser = admin_project_serializers.ProjectModelsSerializers(data = request.data)         if ser.is_valid():             ser.save()         else:             req['status_code'] = 50000             req['msg'] = str(ser.errors)          return Response(req)      def put(self,request,*args,**kwargs):         # 编辑现有项目         req = {             'status_code':20000,             'msg':'修改成功'         }          sid = request.data.get('id')         project_obj = project_models.ProjectModels.objects.filter(id=sid).first()          ser = admin_project_serializers.ProjectModelsSerializers(data=request.data,instance=project_obj)          if ser.is_valid():             print('ser.validated_data:',ser.validated_data)             ser.save()         else:             req['status_code'] = 50000             req['msg'] = str(ser.errors)          return Response(req)      def delete(self,request,*args,**kwargs):         project_id = request.data.get('project_id')         project_obj = project_models.ProjectModels.objects.filter(id=project_id).first()         project_obj.delete()         return Response({             'status_code':20000,             'msg':'删除成功'         })   

serializer.py

 class ProjectStatusModelsSerializers(serializers.ModelSerializer):     # 项目状态序列化器     class Meta:         model = project_models.ProjectStatusModels         fields = '__all__'   class ProjectModelsSerializers(serializers.ModelSerializer):     # 项目序列化器     class Meta:         model = project_models.ProjectModels         fields = '__all__'         depth = 1  

在项目 查询的时候可以返回如下的字段

{   "status_code": 20000,   "code": 0,   "data": [     {       "id": 5,       "status": null,       "project_id": "asdasdasd",       "name": "123123123",       "customer_name": "Abcd",       "evaluation": null,       "start_date": null,       "expiration_date": null,       "create_time": "2021-04-04T23:17:58.433641",       "update_time": "2021-04-04T23:17:58.433666",       "sales_name": null     },     {       "id": 4,       "status": null,       "project_id": "sss03",       "name": "qweqqweasd",       "customer_name": "",       "evaluation": 10000,       "start_date": null,       "expiration_date": null,       "create_time": "2021-04-04T23:17:03.571699",       "update_time": "2021-04-04T23:17:03.571714",       "sales_name": null     },     {       "id": 3,       "status": null,       "project_id": "sss01",       "name": "asasas",       "customer_name": "",       "evaluation": null,       "start_date": null,       "expiration_date": null,       "create_time": "2021-04-04T23:15:31.134011",       "update_time": "2021-04-04T23:15:31.134029",       "sales_name": null     },     {       "id": 2,       "status": {         "id": 2,         "name": "End"       },       "project_id": "0002",       "name": "s0002",       "customer_name": "微创医疗 111",       "evaluation": 500,       "start_date": "2021-04-04",       "expiration_date": "2021-05-11",       "create_time": "2021-04-04T22:43:18.374238",       "update_time": "2021-04-05T11:39:18.852015",       "sales_name": {         "id": 5,         "code": "0003",         "name": "endpein",         "phone": "",         "birthday": "2021-04-02",         "age": 18,         "on_the_job": true,         "identity_card": "",         "work_id": "",         "work_id_date": null,         "work_id_expiry_date": null,         "dormitory_address": "",         "passport_id": "",         "passport_expiry_date": null,         "multiskill_expiry": null,         "csoc_expiry": null,         "multiskill_category": "[]",         "bank_details": "",         "email": "[email protected]",         "remarks": "哈哈哈",         "nationality": null       }     },     {       "id": 1,       "status": {         "id": 6,         "name": "asdasd"       },       "project_id": "0001",       "name": "s01 项目",       "customer_name": "微创医疗",       "evaluation": 1000,       "start_date": "2021-04-29",       "expiration_date": "2021-04-30",       "create_time": "2021-04-04T22:42:51.462897",       "update_time": "2021-04-05T14:34:03.122631",       "sales_name": null     }   ] }  

但是前端传来的数据如下 ,这个数据是 request.data 输出的

<QueryDict: {'csrfmiddlewaretoken': ['ntdydSUNRztDKOKmDSST36oFnSokUFVJG0t9YLXXvQtm6hyYOPT3WHMRPahy6kz8'], 'id': ['1'], 'name': ['s01 项目'], 'project_id': ['0001'], 'customer_name': ['微创医疗'], 'evaluation': ['1000'], 'start_date': ['2021-04-29'], 'expiration_date': ['2021-04-30'], 'status': ['2'], 'sales_name': ['']}>  

但是当 ser.is_valid() 在输入 validated_data 的时候 表中 status、sales_name这 2 个一对多的 ForeignKey 字段就没有了。输出变成了如下样式:

ser.validated_data: OrderedDict([('project_id', '0001'), ('name', 's01 项目'), ('customer_name', '微创医疗'), ('evaluation', 1000), ('start_date', datetime.date(2021, 4, 29)), ('expiration_date', datetime.date(2021, 4, 30))]) 

请问一下,各位高手应该如何修改和调整呢?

大佬有話說 (3)

  • 資深大佬 : Zhuzhuchenyan

    根据官方文档对于 nested serialization 的描述,详见 https://www.django-rest-framework.org/api-guide/serializers/#writing-create-methods-for-nested-representations

    “If you’re supporting writable nested representations you’ll need to write .create() or .update() methods that handle saving multiple objects.”

    所以光有 depth=1 是不够的,需要重写对应的`create`方法

    正好有空,给你个最低限度能用的代码

    “`python

    # models.py
    class Author(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
    return self.name

    class Book(models.Model):
    name = models.CharField(max_length=128)
    author = models.ForeignKey(to=Author, related_name=’books’, on_delete=models.CASCADE)

    def __str__(self):
    return self.name

    # serializers.py

    class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
    model = Author
    fields = ‘__all__’

    class BookSerializer(serializers.ModelSerializer):
    author = AuthorSerializer()

    class Meta:
    model = Book
    fields = ‘__all__’

    def create(self, validated_data):
    author_data = validated_data.pop(‘author’)
    author = Author.objects.get(name=author_data[‘name’])
    return Book.objects.create(author=author, **validated_data)

    # viewset.py

    class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = None
    http_method_names = [‘get’, ‘post’]

    “`

    “`
    # 示例代码 curl
    curl –location –request POST ‘{root_url}/books/’
    –header ‘Content-Type: application/json’
    –data-raw ‘{
    “name”: “Book 2”,
    “author”: {
    “name”: “YYH”
    }
    }’
    “`

    需要注意的是即使 author 里面传递了 ID,这个 ID 也不会出现在 validated_data 中,这个算是 drf 的一个局限性。

    环境:
    djangorestframework==3.12.2
    Django==3.1.3

  • 資深大佬 : Zhuzhuchenyan

    不好意思,不知道为啥没有出现 readme 排版,难道是我使用姿势错了,
    代码缩进都不见了,凑合着看看吧,这个问题只要重新 create 方法一般都能解决

  • 主 資深大佬 : endpain

    @Zhuzhuchenyan 非常感谢,我在仔细看看。跪谢!

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具