Django DRF序列化器或视图中的多表过滤

问题描述 投票:0回答:1

我想要做的是检索与当前用户相关的记录。

我正在使用DRF JWT,因此user_id与JWT sessionStorage一起存储在token中。据我了解,因为使用JWT,会话身份验证不是,所以像request.user这样的东西不起作用。至少我永远不会让它工作,只是被告知将user_id存放在sessionStorage与JWT token。因此,如果我想要检索与当前用户相关的记录,则需要使用sessionStorage.getItem('user_id')POST传递给API。 GET将无法工作,因为1)request.user不起作用,2)不能发送sessionStorage.getItem('user_id')

所以这里是我正在使用的模型,我需要使用一些示例数据进行过滤:

-- Products table
prod_id | prod_name | active
----------------------------
3       | Widget1   | 0
10      | Widget2   | 1
11      | Widget3   | 1

-- Users table
user_id | username
------------------
10011   | joesmith

-- User_to_Products table
user_id | prod_id
-----------------
10011   | 3
10011   | 11

所以应该发生的是React FE通过sessionStorage.getItem('user_id')POST发送到DRF BE,DRF视图有queryset用于User_to_Products,它被序列化,并且prod_idprod_name被发送回客户端以便prod_name可以呈现在React FE中。

这是大局,并且大部分都在发生。但是,如果prod_id处于非活动状态(0),则不应返回。目前,我可以过滤与user_id相关的项目,但它将返回所有prod_id。所以我需要过滤User_to_ProductsProducts

我无法做到这一点。我尝试做类似的事情:

user_id = request.data['user_id']
queryset = UserToProducts.objects.filter(user_id=user_id).filter(products__active=1)

哪个适用于香草Django,但不适用于DRF。它认为products__User_to_Products中的一个字段名称,而不是认为它是一个表。

那我该怎么做呢?

这是我的代码在当前状态,即使不活动,它返回所有prod_id

# ./views.py
class GetHomeAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):
        user_id = request.data['user_id']
        serializer = GetProductsSerializer(UserToProducts.objects.filter(user_id=user_id).prefetch_related('products'), many=True)            
        return Response(serializer.data)

# ./serializers.py
from .models import *

class GetProductsSerializer(ModelSerializer):
prod_name = CharField()
prod_id = IntegerField()

class Meta:
    model = UserToProducts
    fields = [
        'prod_id',
        'prod_name'
    ]

# ./models.py
User = get_user_model()

class Products(models.Model):
    prod_id = models.AutoField(primary_key=True)
    prod_name = models.CharField(max_length=255, blank=True, null=True)
    active = models.IntegerField(blank=False)
    users = models.ManyToManyField(User, through='UserToProducts')

    def __str__(self):
        return self.prod_name

    class Meta:
        db_table = 'Products'

class UserToProducts(models.Model):
    user_id = models.ForeignKey(User, related_name='user', db_column='user_id', null=True)
    prod_id = models.ForeignKey(Products, related_name='products', db_column='prod_id', null=True)

    def __str__(self):
        return u'%s' % self.prod_id

    class Meta:
        db_table = 'User_to_Products'
        unique_together = ('user_id', 'prod_id')
        ordering = ['-prod_id']
python django django-rest-framework jwt
1个回答
1
投票

request.user也应该使用JWT身份验证。您必须确保在REST_FRAMEWORK配置dict中添加了其身份验证类,如下所示:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        # ...
    ),
}

要从外键字段渲染字段,可以使用序列化字段的source属性,如下所示:

# ./serializers.py
from rest_framework.serializers import *
from .models import *

class GetProductsSerializer(ModelSerializer):
    prod_name = CharField(source='prod.name')
    prod_id = IntegerField(source='prod.id')

    class Meta:
        model = UserToProducts
        fields = [
            'prod_id',
            'prod_name'
        ]

此外,如果您使用的是模型字段而不是序列化程序字段,那么您在此处发布的序列化程序并不清楚。确保在序列化程序中使用序列化程序字段。

关于你的模型,你不应该在外键字段中附加“_id”,因为Django会为你抽象。在引擎盖下,它将创建一个名为{{the_field}} _ id的正整数字段。您可以将外键字段用作模型实例。这条路:

class UserToProducts(models.Model):
    user = models.ForeignKey(User, related_name='users', db_column='user_id', null=True)
    prod = models.ForeignKey(Products, related_name='products', db_column='prod_id', null=True)

    def __str__(self):
        return u'%s' % self.prod.id

    class Meta:
        db_table = 'User_to_Products'
        unique_together = ('user', 'prod')
        ordering = ['-prod__id']

这样,如果你有一个UserToProducts实例user_to_products并想要打印其产品名称,你可以做print(user_to_products.prod.name)。 Django将自动为您检索数据库中的产品。

© www.soinside.com 2019 - 2024. All rights reserved.