在Django REST框架中返回关系数据的建议

rbl8hiat  于 2023-01-22  发布在  Go
关注(0)|答案(2)|浏览(127)

我是Django/Django REST FW的新手(也是这个社区的新手)。我已经花了很多时间阅读文档,但在这一点上我还在原地打转。我提前为在这里如此冗长道歉。
我的后端数据库是Postgres。我有3个模型,UserItemShoppingList。我需要Item包含说明(item_name字段)及其位置。用户将选择一个项目并将其添加到当天的ShoppingList中。其想法是,用户在获得该项目后将其“勾选”,然后将其“删除”从X1 M6 N1 X的Angular 来看。
这就是我遇到麻烦的地方:我不想复制shopping_list表中的item_nameitem_location字段,但我需要在购物列表(shopping_lists.py)的视图中显示这些字段。
ItemShoppingList之间分别存在一对多关系。Item对象被视为存储每个物料的说明和位置的“主物料表”。ShoppingList对象保存这些“主物料”的临时列表。我需要一个包含ShoppingList中所有字段和Item中2个或更多字段的查询集。
我认为这就是Django REST FW所认为的反向关系。我尝试了对序列化器和模型进行各种更改(包括将Item序列化器添加到ShoppingList序列化器),但得到了各种错误。
型号/item.py:

from django.db import models
from django.contrib.auth import get_user_model

class Item(models.Model):
    item_name = models.CharField(max_length=50, db_index=True)
    item_location = models.CharField(max_length=10, blank=True, db_index=True)
    item_class = models.CharField(max_length=20, blank=True)
    # This is a relationship with User model
    shopper_id = models.ForeignKey(
        get_user_model(),
        on_delete=models.CASCADE
    )

    def __str__(self):
        return f"item_name: {self.item_name}, item_location: {self.item_location}, shopper_id: {self.shopper_id}"

模特/购物清单.py:

from django.db import models
from django.contrib.auth import get_user_model
from .item import Item

class ShoppingList(models.Model):
    item_num = models.ForeignKey(
        'Item',
        on_delete=models.DO_NOTHING # we don't want to delete the item from the "master" item list, just from this shopping list
    )
    # This is a relationship with user model. 
    shopper_id = models.ForeignKey(
        get_user_model(),
        on_delete=models.CASCADE # ...but we do want to delete the item if the user goes away as items are user-specific
    )
    item_qty = models.PositiveIntegerField()
    item_complete = models.BooleanField(default=False)
    added_on = models.DateField(auto_now=True)
    # setting list_num to blank=True for this version
    list_num = models.PositiveIntegerField(blank=True)

    def __str__(self):
        return f"item_num: {self.item_num}, shopper_id: {self.shopper_id}, item_qty: {self.item_qty}, item_complete: {self.item_complete}"

序列化程序/item.py:

from rest_framework import serializers
from ..models.item import Item

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('id', 'item_name', 'item_location', 'item_class', 'shopper_id')

序列化器/购物清单.py:

from rest_framework import serializers
from ..models.shopping_list import ShoppingList

class ShoppingListSerializer(serializers.ModelSerializer):
    class Meta:
        model = ShoppingList
        fields = ('id', 'item_num', 'shopper_id', 'item_qty', 'item_complete', 'added_on', 'list_num')

获取错误 * 属性错误:当我在下面的views/shopping_lists.py中执行class ShoppingListItemView中的GET方法时,无法通过ShoppingList示例 * 访问管理器:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from rest_framework.exceptions import PermissionDenied
from ..models.shopping_list import ShoppingList
from ..serializers.shopping_list import ShoppingListSerializer
from ..models.item import Item
from ..serializers.item import ItemSerializer

class ShoppingListsView(APIView):
    def get(self, request, list_num):
        shopping_items = ShoppingList.objects.filter(shopper_id=request.user.id)
        shopping_list_items = shopping_items.filter(list_num=list_num)
        data = ShoppingListSerializer(shopping_list_items, many=True).data
        return Response(data)

    def post(self, request):
        request.data['shopper_id'] = request.user.id
        list_item = ShoppingListSerializer(data=request.data, partial=True)
        if list_item.is_valid():
            list_item.save()
            return Response(list_item.data, status=status.HTTP_201_CREATED)
        else:
            return Response(list_item.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, list_num):
        shopping_items = ShoppingList.objects.filter(shopper_id=request.user.id)
        shopping_list_items = shopping_items.filter(list_num=list_num)
        response_data = shopping_list_items.delete()
        return Response(response_data, status=status.HTTP_204_NO_CONTENT)

class ShoppingListsAllView(APIView):
    def get(self, request):
        shopping_items = ShoppingList.objects.filter(shopper_id=request.user.id)
        data = ShoppingListSerializer(shopping_items, many=True).data
        return Response(data)

class ShoppingListItemView(APIView):
    def get(self, request, pk):
        list_item = get_object_or_404(ShoppingList, pk=pk)
        if request.user != list_item.shopper_id:
            raise PermissionDenied('Unauthorized, this item belongs to another shopper')
        else:
            list_entry = list_item.objects.select_related('Item').get(id=pk)
            print(list_entry)
            data = ShoppingListSerializer(list_item).data
            return Response(data)

    def delete(self, request, pk):
        list_item = get_object_or_404(ShoppingList, pk=pk)
        if request.user != list_item.shopper_id:
            raise PermissionDenied('Unauthorized, this item belongs to another shopper')
        else:
            list_item.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)

    def patch(self, request, pk):
        list_item = get_object_or_404(ShoppingList, pk=pk)
        if request.user != list_item.shopper_id:
            raise PermissionDenied('Unauthorized, this item belongs to another shopper')
        else:
            request.data['shopper_id'] = request.user.id
            updated_list_item = ShoppingListSerializer(list_item, data=request.data, partial=True)
            if updated_list_item.is_valid():
                updated_list_item.save()
                return Response(updated_list_item.data)
            else:
                return Response(updated_item.errors, status=status.HTTP_400_BAD_REQUEST)
2lpgd968

2lpgd9681#

如果只想显示ShoppingList中某个项目的几个属性,则可以在序列化程序中使用SerializerMethodField方法
这将作为-

class ShoppingListSerializer(serializers.ModelSerializer):
    itemProperty1 = serializers.SerializerMethodField()
    itemProperty2 = serializers.SerializerMethodField()

    class Meta:
        model = ShoppingList
        fields = ('id', "itemProperty1", "itemProperty2", 'more_fields')
   
    def get_itemProperty1(self, instance):
        return instance.item.anyPropertyOfItem if instance.item else ''

    def get_itemProperty2(self, instance):
        return instance.item.anyPropertyOfItem if instance.item.else ''

anyPropertyOfItem可以是项目模型中的任何内容。通过这种方式设置序列化程序,ShoppingList视图将自动显示2个新字段。
或者你也可以在模型中的@属性的帮助下定义只读字段来获得必需的字段。
如果你想在ShoppingList视图中显示商品的所有属性,你可以在这里写,将编辑我的答案。这里你需要使用related_name并获取ShoppingList序列化程序中的商品序列化程序作为额外的字段。

aiqt4smr

aiqt4smr2#

对于反向关系,应在定义模型或使用后缀_set时使用related_name。
related_name属性指定了用户模型到你的模型的反向关系的名称,如果你不指定related_name,Django会自动创建一个使用你的模型名加上后缀_set的反向关系
What is related_name used for?复制到Wogan

相关问题