AttributeError в / apiv2 / api / processorder / order / - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь отправить несколько данных в свою базу данных, используя Django Rest framework (DRF).

AttributeError в / apiv2 / api / processorder / order / Got AttributeError при попытке получить значение для поля subcategory на сериализаторе MyProcessOrderSerializer. Поле сериализатора может быть названо неправильно и не соответствовать ни одному атрибуту или ключу в экземпляре list. Исходный текст исключения был: объект 'list' не имеет атрибута 'subcategory'.

models.py

class SubCategory(models.Model):

    category = models.ForeignKey(Category, related_name='subcategory', on_delete=models.CASCADE)
    name = models.CharField("Food Name", max_length=50, help_text="Name of The Food")    
    price = models.DecimalField("Food Price", max_digits=5, decimal_places=2)
    quantity = models.PositiveIntegerField("Qty.", help_text="Quantity of the food Item you want")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return f'{self.name}'

    class Meta:
        verbose_name = 'SubCategory'
        verbose_name_plural = 'SubCategories'

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    bike = models.ForeignKey(User, related_name='bike', on_delete=models.CASCADE, blank=True, null=True)
    package = models.ForeignKey(PackageType, related_name='package', on_delete=models.CASCADE, blank=True, null=True)
    total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0000.0)  
    qty = models.PositiveIntegerField(default=1)
    shipping_address = models.CharField("Delivery Address", max_length=150)
    paid = models.BooleanField(default=False)
    ordernote = models.TextField("Order Notes", null=True)
    shipped = models.BooleanField(default=False)
    complete = models.BooleanField(default=False) 
    received = models.BooleanField(default=False)
    refund_requested = models.BooleanField(default=False)
    refund_granted = models.BooleanField(default=False)
    ref_code = models.CharField(max_length=20, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


    class Meta:
        ordering = ('-created_at',)

    def __str__(self):
        return '{}'.format(self.id)


    def order(self):
        if not hasattr(self, '_order'):
            self._order = self.order.all()
        return self._order

    

    '''
    def get_total_cost(self):
        total_cost = sum(orders.get_cost() for orders in self.order.all())
        return total_cost

    '''


class ProcessOrder(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    order = models.ForeignKey(Order, related_name='order', on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField("Qty.", default=1, help_text="Quantity of the food Item you want")
    #category = models.ForeignKey(Category, related_name='category', on_delete=models.CASCADE)
    subcategory = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'{self.order} -- {self.subcategory.name}'

serializers.py

class MyProcessOrderSerializer(serializers.ModelSerializer):

    #subcategory_name = serializers.RelatedField(source='subcategory.id', read_only=True)
    #subcategory_set = SubCategoryOrderSerializer(many=True)


    class Meta:
        model = ProcessOrder
        fields = ('quantity', 'subcategory', 'user')

        read_only_fields = ('user', ) 

    def create(self, validated_data):
        return ProcessOrder.objects.create(**validated_data)

view.pf

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def processorder_view(request):
    orderuser = User.objects.get(id=request.user.id)    
    serializer = MyProcessOrderSerializer(data=request.data, many=True)
   
    if serializer.is_valid():
        order = Order.objects.create(user=orderuser, ref_code=create_ref_code())
        order.save()
        processorder = serializer.save(order=order, user=orderuser)
        return Response(MyProcessOrderSerializer(processorder).data, status=status.HTTP_201_CREATED)
    else:        #return Response("Process Order Created Successfully")
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Сейчас я пытаюсь сделать такой POST, но получаю указанную выше ошибку.

[{"количество": 16, "подкатегория": 1}, {"количество" : 14, «подкатегория»: 3}

]

enter image description here

введите описание изображения здесь

Ответы [ 3 ]

0 голосов
/ 06 августа 2020

Я думаю, что проблема проявляется в request.data в этой строке:

      serializer = MyProcessOrderSerializer(data=request.data, many=True)

Вы должны oop пропустить свой список объектов и передать только объект, а не весь список.

пример:

{"список _": [{"количество": 7, "подкатегория": 3}, {"количество": 7, "подкатегория": 3}]}

Для получения первого объекта из запроса:

   request.data.get('list_')[0]
0 голосов
/ 07 августа 2020

Мне удалось решить проблему с этим кодом как в моих представлениях, так и в сериализации

views.py

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def processorder_view(request):
    orderuser = User.objects.get(id=request.user.id) 
    data = request.data
    
    order = Order.objects.create(user=orderuser, ref_code=create_ref_code())
    

    
    if isinstance(data, list):
        serializer = MyProcessOrderSerializer(data=request.data, many=True)
        
    else:
        serializer = MyProcessOrderSerializer(data=request.data)
        
    if serializer.is_valid():
        processorder = serializer.save(order=order, user=request.user)
        return Response(status=status.HTTP_201_CREATED)
        #return HttpResponse("Question created", status=201)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

serializers.py

class MyProcessOrderSerializer(serializers.ModelSerializer):

    #subcategory_name = serializers.RelatedField(source='subcategory.id', read_only=True)
    #subcategory_set = SubCategoryOrderSerializer(many=True)
    #subcategory = serializers.StringRelatedField(source='subcategory.id', read_only=True)



    class Meta:
        model = ProcessOrder
        fields = ('quantity', 'subcategory', 'user')

        read_only_fields = ('user', ) 

    def create(self, validated_data):
        return ProcessOrder.objects.create(**validated_data)

Затем , Я смог отправить несколько данных с этим образцом.

[
    {
        "subcategory": 1,
        "quantity": 12
    },
    {
        
        "subcategory": 3,
        "quantity": 12
    }
]
0 голосов
/ 06 августа 2020

Вы должны явно указать отношение в сериализаторе либо с помощью одного из встроенных сериализаторов:

Отношения сериализатора

class MyProcessOrderSerializer(serializers.ModelSerializer):
    # StringRelatedField and PrimaryKeyRelatedField are some of the built in ones.
    subcategory = serializers.StringRelatedField(source='subcategory.id', read_only=True)
    user = serializer.PrimaryKeyRelatedField()

    class Meta:
        model = ProcessOrder
        fields = ('quantity', 'subcategory', 'user')

        read_only_fields = ('user', ) 

    def create(self, validated_data):
        # If you want to accect new subcategory object via the endpoint you need further action here, see the docs.
        return ProcessOrder.objects.create(**validated_data)

или путем создания пользовательский сериализатор подкатегорий, а затем в сериализаторе:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('id', 'email', 'password', 'first_name', 'last_name')
class SubCategorySerializer(serializers.ModelSerializer):
    class Meta:
      fields = # whatever fields youd'e like to include

class MyProcessOrderSerializer(serializers.ModelSerializer):
    # StringRelatedField is One of the built in ones.
    sybcategory = SubCategorySerializer()
    user = UserSerializer()

    class Meta:
        model = ProcessOrder
        fields = ('quantity', 'subcategory', 'user')

        read_only_fields = ('user', ) 

    def create(self, validated_data):
        # If you want to accect new subcategory object via the endpoint you need further action here, see the docs.
        return ProcessOrder.objects.create(**validated_data)

И, я заметил, что у вас есть внешний ключ для пользователя в технологическом порядке и самом порядке,

Вы можете удалить поле пользователя из технологического порядка и получить к нему доступ через отношение порядка, для этого вы можете указать поле пользователя в сериализаторе подкатегории и сериализатор подкатегории в сериализаторе порядка процесса, как я показал выше.

И если я понимаю цель создания процесса В модели заказа отношение должно быть «Один к одному», а не внешним ключом, но, возможно, я не вижу здесь всей картины.

...