Django rest framework请求参数默认使用用户i
背景
刚开始学习了drf的初步使用,就想到了一个问题,如果所有的参数都由前端来指定是不符合规范的。
比如:
用户的商品添加到购物车,这是个非常常规的操作。正常情况下,我们拿到商品的id,然后取出来user的id就可以存数据库了。
但是现在是使用的DRF框架,表里面的字段是肯定有一个user_id字段的,这个时候,如果把user_id放给了前端传参,那么问题就出现了。
- 前端传的user_id不是此用户的id,而是别的用户的id,这是个非常大的问题,所以这个user_id不能由前端指定。
- user_id必须由后端从session里面获取,然后直接赋值,拿来存储。并且前端不应该传这个参数。所以在serializers里面,应该把user_id排除或者是设置为
read_only=True
。
于是,我就在怎么把这个user_id存进去数据库上花了一些时间进行探索。
修改request.data
想着参数是从request.data来的,所以就是在这里给user_id赋值就好了:request.data['user_id'] = request.user.id
然而,一提交参数,直接就报错了:This QueryDict instance is immutable
。嗷,原来不能改啊,经过我一番搜索,我还是给它改了:
request.data._mutable = True
request.data['user_id'] = str(request.user.id)
request.data._mutable = False
然后继续提交,发现数据库报错:(1048, "Column 'user_id' cannot be null")
。
看来赋值没成功,print(serializer)
发现在serializers的data里面,是有我加入的数据的。
那问题应该是出在我的serializers.py
里面,因为我把user_id = UserSerializers(read_only=True)
,既然是read_only,drf应该是给我在调用serializer.is_valid(raise_exception=True)
时候,清空了不需要的字段。
解决办法
又查了很多资料,发现确实比较难搞定这个问题,好在有一篇文章给了个官方文档的提示:https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/ 。解决办法也比较简单
在view.py的ViewSet里面,重写perform_create方法,在save的时候,指定参数内容。
def perform_create(self, serializer):
serializer.save(user=self.request.user)
# serializer.save(user_id=self.request.user.id) 这样也可以
然后再次post,通过了,没问题。官方给的方法也是这样,这个办法非常棒也非常直接,如果还有其他的参数,也可以一起加进去。
其他
在处理参数的时候,还遇到了一个问题,只要一用到serializer.data,就一直报错When a serializer is passed a `data` keyword argument you must call `.is_valid()` before attempting to access the serialized `.data` representation. You should either call `.is_valid()` first, or access `.initial_data` instead.
即使我只是print(serializer.data)
也会报错,这个安全措施确实是做得非常好。要改data那就只有在request.data里面改,或者根据提示使用print(serializer.inital_data)
这样就可以避免报错。