
大家好,我在使用 django drf 的时候遇到了一个问题,找了一堆资料,暂时还没找到好的解决方法,希望有懂的兄弟可以给指点一下。非常感谢。
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',) 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':'删除成功' }) 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": nll }, { "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))]) 请问一下,各位高手应该如何修改和调整呢?
1 Zhuzhuchenyan 2021-04-05 16:49:52 +08:00 根据官方文档对于 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 |
2 Zhuzhuchenyan 2021-04-05 16:52:07 +08:00 不好意思,不知道为啥没有出现 readme 排版,难道是我使用姿势错了, 代码缩进都不见了,凑合着看看吧,这个问题只要重新 create 方法一般都能解决 |
3 endpain OP @Zhuzhuchenyan 非常感谢,我在仔细看看。跪谢! |