繁体   English   中英

如何将“user_id”传递给 CustomerSerializer?

[英]How do I pass 'user_id' to CustomerSerializer?

我不知道如何从requests.user.id传递user_id并在CustomerSerializer中使用它来将 object 保存到数据库中。 该错误源于user_id存在于数据库中的客户表中,但它没有显示为要在 rest_framework API 前端传递的字段(只有phoneprofile_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM