【问题标题】:Multiple table filtering in Django DRF serializer or viewDjango DRF 序列化器或视图中的多表过滤
【发布时间】:2018-05-08 17:02:24
【问题描述】:

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

我正在使用 DRF JWT,因此 user_id 与 JWT token 一起存储在 sessionStorage 中。据我了解,因为正在使用 JWT,会话身份验证不是,所以像 request.user 这样的东西不起作用。至少我永远无法让它工作,只是被告知将 user_id 与 JWT token 一起存储在 sessionStorage 中。因此,如果我想检索与当前用户相关的记录,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 通过POSTsessionStorage.getItem('user_id') 发送到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】:

    request.user 也应该与 JWT 身份验证一起使用。您必须确保在 REST_FRAMEWORK 配置字典中添加了它的身份验证类,如下所示:

    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 将自动为您检索数据库中的产品。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      • 2022-11-29
      • 1970-01-01
      • 2019-03-18
      相关资源
      最近更新 更多