【问题标题】:Reading in related data from table in foreign key relationship in Django REST Framework从Django REST框架中的外键关系表中读取相关数据
【发布时间】:2017-11-15 20:05:08
【问题描述】:

确实在为此苦苦挣扎,而且看起来应该非常直截了当。基本上,我只是尝试将产品与用户关联,然后将这些产品中的每一个的short_name 呈现在 FE 上。

我有一张包含user_idprod_id 的表。该表可能如下所示:

user_id | prod_id
-----------------
2       | 42
2       | 2
2       | 21
13      | 7
13      | 17
13      | 2

user_idmodels.ForeignKeyUser 表,prod_idmodels.ForeignKeyProducts 表。更好的是,这里是模型:

# ./home/models.py
from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()

class Product(models.Model):
    id = models.AutoField(primary_key=True)
    code = models.CharField(unique=True, max_length=16)
    name = models.CharField(max_length=255, blank=True, null=True)
    short_name = models.CharField(max_length=128)
    updated = models.DateTimeField(blank=True, null=True)
    created = models.DateTimeField(blank=True, null=True)   

    def __str__(self):
        return self.short_name

    class Meta:
        db_table = 'Product'

class UserToProduct(models.Model):
    user = models.ForeignKey(User, related_name='user_name', db_column='user_id', null=True)
    prod = models.ForeignKey(Product, related_name='prod_name', db_column='prod_id', null=True)

    class Meta:
        db_table = 'User_to_Product'
        unique_together = ('user', 'prod')

应该发生的是 React 前端根据谁登录到 Django/DRF 后端发送user_id。这一切都很好。以下是相关视图:

# ./home/views.py
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST
from rest_framework.views import APIView

from .serializers import GetProductSerializer
from .models import Home

class GetHomeAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):
        serializer = GetProductSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            return Response(serializer.data, status=HTTP_200_OK)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

从那里,它应该只是拉出与它们相关的产品列表,然后从Product 模型中读取short_name,或者实际上只是一个我可以解析出short_name 的对象。

这是序列化程序:

# ./home/serializers.py
from rest_framework.serializers import (
    IntegerField,
    ModelSerializer, 
    SerializerMethodField,
    StringRelatedField, 
)

from .models import *

class GetProductSerializer(ModelSerializer):
    prod_name = StringRelatedField(many=True, required=False)
    product = SerializerMethodField('get_products')

    class Meta:
        model = UserToProduct
        fields = ('user', 'prod', 'prod_name')

    def get_products(self, obj):
        products = UserToProduct.objects.filter(user=data['user'])
        return products

这种特殊的变化导致:NameError: name 'data' is not defined

get_products() 更改为:

# for testing reasons
products = UserToProduct.objects.filter(user=2) 

这会导致:KeyError: 'prod_name'

无论如何,我在这方面花费的时间比我愿意承认的要多。这是一些非常基本的东西。我已经尝试了几十种变化。我会继续努力并发布我尝试过的内容和错误。

另外,这是我阅读了几十遍的参考文档:

http://www.django-rest-framework.org/api-guide/relations/

http://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/

也参考了无数其他关于此的 SO 问题/答案,但不起作用。

编辑:可能已经尝试了几十件事,最终能够从服务器获得序列化响应;但是,它没有引入short_name。我只做了修改:

# ./home/models.py
class Product(models.Model)
    ...
    users = models.ManyToManyField(User, through='UserToProduct')

# ./home/serializers.py
class GetProductSerializer(ModelSerializer):
    user = IntegerField() # have to do this otherwise it returns the username and not the id
    prod = SerializerMethodField()

    class Meta:
        model = UserToProduct
        fields = [
            'user',
            'prod',

        ]

    def get_prod(self, obj):
        prod = UserToProduct.objects.filter(user=obj['user']).values('prod')
        print(prod)
        return prod

另外,需要注意的是,将get_prod() 保留为:

prod = UserToProduct.objects.filter(user=obj['user'])

结果为:TypeError: Object of type 'UserToProduct' is not JSON serializable。但是,它确实在print(prod) 中列出了short_name

【问题讨论】:

  • UserToProduct 是多对多关系的直通表,应该这样声明。

标签: django django-models django-rest-framework django-views


【解决方案1】:

好吧,终于觉得我搞定了。虽然它非常慢,并且需要大约 5 秒才能返回看起来确实不正确的信息。这对于数据量来说太长了。

无论如何,这就是它为我工作的原因:

# ./home/views.py
...
def post(self, request, *args, **kwargs):
    user = request.data['user']
    serializer = GetProductSerializer(UserToProduct.objects.filter(user=user).prefetch_related('prod'), many=True)
    return Response(serializer.data)

# ./home/serializers.py
class GetProductSerializer(ModelSerializer):
    prod = CharField() # otherwise it was using prod_id number

    class Meta:
        model = UserToProduct
        fields = [
            'prod'
        ]

比我尝试的要简单...刚刚解决了速度问题。

编辑:在这篇 SO 帖子的帮助下修复了速度问题:

Optimizing database queries in Django REST framework

将我的查询修改为以下内容:

UserToProduct.objects.filter(user=user).prefetch_related('prod')

它从 4.75 秒下降到 1.5 秒。呸呸呸。

【讨论】:

    猜你喜欢
    • 2015-12-07
    • 2017-08-19
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多