[英]How do I pass 'user_id' to CustomerSerializer?
我不知道如何从requests.user.id
传递user_id
并在CustomerSerializer
中使用它来将 object 保存到数据库中。 该错误源于user_id
存在于数据库中的客户表中,但它没有显示为要在 rest_framework API 前端传递的字段(只有phone
和profile_image
可以)。
这是客户 model:
class Customer(models.Model):
phone = models.CharField(max_length=14)
profile_image = models.ImageField(blank=True, null=True)
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
这是视图集:
class CustomerViewSet(ModelViewSet):
queryset = Customer.objects.all()
permission_classes = [permissions.IsAdminUser]
serializer_class = CustomerSerializer
# Only admin users can make requests other than 'GET'
def get_permissions(self):
if self.request.method == 'GET':
return [permissions.AllowAny()]
return [permissions.IsAdminUser()]
@action(detail=False, methods=['GET', 'PUT'])
def me(self, request):
customer, created = Customer.objects.get_or_create(user_id=request.user.id)
if request.method == 'GET':
serializer = CustomerSerializer(customer)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
...这是序列化程序:
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ['id', 'user_id', 'profile_image', 'phone']
```python
... and when I try to save a new customer by sending a POST request to the endpoint with the following data:
```json
{
"profile_image": "Images/image.png",
"phone": "009293930"
}
我收到以下错误:
IntegrityError at /api/customers/
(1048, "Column 'user_id' cannot be null")
Request Method: POST
Request URL: http://127.0.0.1:8000/api/customers/
Django Version: 4.0.6
Exception Type: IntegrityError
Exception Value:
(1048, "Column 'user_id' cannot be null")
Exception Location: /home/caleb/.local/share/virtualenvs/Cribr-svgsjjVF/lib/python3.8/site-packages/pymysql/err.py, line 143, in raise_mysql_exception
Python Executable: /home/caleb/.local/share/virtualenvs/Cribr-svgsjjVF/bin/python
Python Version: 3.8.10
Python Path:
['/home/caleb/Desktop/Cribr',
'/home/caleb/Desktop/Cribr',
'/snap/pycharm-professional/290/plugins/python/helpers/pycharm_display',
'/usr/lib/python38.zip',
'/usr/lib/python3.8',
'/usr/lib/python3.8/lib-dynload',
'/home/caleb/.local/share/virtualenvs/Cribr-svgsjjVF/lib/python3.8/site-packages',
'/snap/pycharm-professional/290/plugins/python/helpers/pycharm_matplotlib_backend']
Server time: Thu, 28 Jul 2022 23:38:53 +0000
我认为这里的问题是序列化程序 class 没有从 POST 请求中获取user_id
值。 我尝试通过上下文 object (即context={'user_id': request.user.id}
)从视图集中将request.user.id
传递给序列化程序,但我不知道如何将其添加到已验证的序列化程序传递给save
方法的数据。
对此问题的任何帮助将不胜感激。 提前致谢。
使用 DRF 和视图集的好处是大部分工作已经为您完成。 在这种情况下,您通常只需要调整一些东西就可以让它按照您想要的方式工作。 我在下面为您重新编写了您的解决方案:
class CustomerViewSet(ModelViewSet):
queryset = Customer.objects.all()
permission_classes = [permissions.IsAdminUser]
serializer_class = CustomerSerializer
# Only admin users can make requests other than 'GET'
def get_permissions(self):
if self.request.method == 'GET':
return [permissions.AllowAny()]
return [permissions.IsAdminUser()]
def get_object(self):
customer, created = Customer.objects.get_or_create(user_id=self.request.user.id)
return customer
@action(detail=False, methods=['GET'])
def me(self, request):
return self.retrieve(request)
来自 DRF 文档:
ModelViewSet class 继承自 GenericAPIView 并通过混合各种 mixin 类的行为包括各种操作的实现。
ModelViewSet class 提供的动作有.list()、.retrieve()、.create()、.update()、.partial_update() 和.destroy()。
ModelViewSet
还将为您设置一个 urlconf,除了list
之外,它将期望在 url 中提供 object pk(主键),以允许视图知道您正在尝试访问的数据库中的哪些资源。 在您的情况下,您希望根据请求中提供的身份验证凭据来确定该资源。 为此,我们可以重写get_object
以根据经过身份验证的用户的 id 获取或创建客户。
我们所做的下一个更改是为GET
方法定义我们的操作。 我们希望能够检索资源,而无需在 url conf 中指定 pk,因此detail=False
。 然后我们可以简单地从这个动作中调用内置的retrieve
function,这反过来将使用get_object
来获取并返回客户 object。
第三,您的PUT
请求将被定向到从ModelViewSet
继承的update
,因此您无需在此处执行任何操作,因为您已经覆盖get_object
。
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
最后,您希望将序列化程序上的user
设置为只读(或完全删除),因为这应该始终根据请求中传递的凭据进行设置。
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ['id', 'user_id', 'profile_image', 'phone']
read_only_fields = ['user_id']
查看从 DRF 类继承的所有函数的一个很好的资源是https://www.cdrf.co/ 。
祝你好运,希望这会有帮助
好的,我设法通过覆盖序列化程序中的 create 方法来解决它。 我添加了以下内容:
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ['id', 'user_id', 'profile_image', 'phone']
read_only_fields = ['user_id']
# NEW ---------------------------------
def create(self, validated_data):
user = self.context['request'].user
customer = Customer.objects.filter(user_id=user)
if customer.exists():
raise serializers.ValidationError(
'Customer already exists')
else:
customer = Customer.objects.create(
user=user, **validated_data)
return customer
object 现在保存得很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.