Я пытаюсь создать заказ, отправляя его как POST-запрос через мой DRF API, но продолжаю получать ошибки "" POST / shop / orders / HTTP / 1.1 "400 81 ".
Ошибка говорит "{" total_price ": [" Это поле обязательно для заполнения. "]," Puppies ": [" Это поле обязательно для заполнения. "]}" , даже если я его добавляю.
GET работает нормально, но у меня есть только заказы, которые я написал в БД вручную.
Наш проект - вымышленный интернет-магазин, где вы можете положить собачек в корзину и заказать их. У нас есть три основные модели: пользователи, заказы и щенки. Поскольку у каждого заказа есть список щенков, и у каждого щенка есть свое количество, нам была нужна промежуточная модель для двух, поскольку простой ManyToManyField, очевидно, не может обрабатывать дополнительные столбцы. Это усложняет ситуацию (по крайней мере, для новичка в Django).
Я не могу найти ничего в интернете для этого особого случая. Я пытался заставить это работать почти неделю, и я не вижу, что я делаю неправильно.
models.py:
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Puppy(models.Model):
name = models.CharField(max_length=30)
price = models.DecimalField(max_digits=6, decimal_places=2)
image_url = models.CharField(max_length=200)
age = models.IntegerField(null=True)
weight = models.IntegerField(null=True)
description_de = models.CharField(max_length=500, null=True)
description_en = models.CharField(max_length=500, null=True)
def __str__(self):
return self.name
class Order(models.Model):
total_price = models.DecimalField(max_digits=9, decimal_places=2)
puppies = models.ManyToManyField(Puppy, through='PuppyOrder')
date = models.DateTimeField(auto_now_add=True, blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='orders')
def __str__(self):
return str(self.id)
class PuppyOrder(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
puppy = models.ForeignKey(Puppy, on_delete=models.CASCADE)
amount = models.IntegerField()
def __str__(self):
return str(self.id)
class Address(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
country = models.CharField(max_length=30, blank=True)
street = models.CharField(max_length=30, blank=True)
zip = models.CharField(max_length=10, blank=True)
city = models.CharField(max_length=30, blank=True)
@receiver(post_save, sender=User)
def create_user_address(sender, instance, created, **kwargs):
if created:
Address.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_address(sender, instance, **kwargs):
instance.address.save()
Получить в реакции:
async function createOrder(order) {
order = order.map(element =>
element = {'puppy' : element.puppy.id, 'amount': element.amount}
)
let orderReq = {"total_price": "500.00", "puppies": order}
console.log(JSON.stringify(orderReq))
const res = await fetch(REACT_APP_BACKEND_URL + `/shop/orders/`, {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ orderReq })
})
return res.json()
}
Результат Console.log: {"total_price": "500.00", "puppies": [{"puppy": 2, "amount": 3}, {"puppy": 4, "amount" : 4}]}
«500,00» - это просто значение заполнителя. Следующим шагом будет поиск места для расчета total_price.
views.py:
from shop.models import Puppy, Order
from django.contrib.auth.models import User
from rest_framework import permissions, status, viewsets, generics
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.serializers import VerifyJSONWebTokenSerializer
from .serializers import UserSerializer, UserSerializerWithToken, OrderSerializer, PuppySerializer
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'orders': reverse('order-list', request=request, format=format),
'puppies': reverse('puppy-list', request=request, format=format),
})
class OrderList(generics.ListCreateAPIView):
print("Test")
queryset = Order.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = OrderSerializer
def get_queryset(self):
if self.request.user is None or self.request.user.is_anonymous:
self.request.user = get_request_user_and_validate_token(self)
return Order.objects.all().filter(user=self.request.user)
def perform_create(self, serializer):
print(self.request.data)
if self.request.user is None or self.request.user.is_anonymous:
self.reqest.user = get_request_user_and_validate_token(self)
if serializer.is_valid():
print('Creating new order...')
serializer.create(user=self.request.user, puppies=self.request.data)
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class OrderDetail(generics.RetrieveAPIView):
permission_classes = (permissions.AllowAny,)
queryset = Order.objects.all()
serializer_class = OrderSerializer
def get_queryset(self):
if self.request.user is None or self.request.user.is_anonymous:
self.request.user = get_request_user_and_validate_token(self)
return Order.objects.all().filter(user=self.request.user)
class UserList(generics.ListAPIView):
queryset = User.objects.all().select_related('address')
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all().select_related('address')
serializer_class = UserSerializer
class PuppyList(generics.ListAPIView):
permission_classes = (permissions.AllowAny,)
queryset = Puppy.objects.all()
serializer_class = PuppySerializer
class PuppyDetail(generics.RetrieveAPIView):
permission_classes = (permissions.AllowAny,)
queryset = Puppy.objects.all()
serializer_class = PuppySerializer
def get_request_user_and_validate_token(self):
print(self.request.user)
token = self.request.META.get('HTTP_AUTHORIZATION', " ").split(' ')[1]
data = {'token': token}
try:
valid_data = VerifyJSONWebTokenSerializer().validate(data)
print(valid_data['user'])
return valid_data['user']
except ValidationError as v:
print("validation error", v)
serializers.py
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from django.contrib.auth.models import User
from django.db import models
from .models import Order, Puppy, PuppyOrder
class UserSerializer(serializers.ModelSerializer):
orders = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = User
fields = ('id', 'username', 'orders')
class UserSerializerWithToken(serializers.ModelSerializer):
# Code dealing with JWT token creation ...
class PuppySerializer(serializers.ModelSerializer):
description = serializers.SerializerMethodField()
def get_description(self, puppy):
return {'DE': puppy.description_de, 'EN': puppy.description_en}
class Meta:
model = Puppy
fields = ('id', 'name', 'price', 'image_url', 'age', 'weight', 'description')
class PuppyOrderSerializer(serializers.ModelSerializer):
puppy = serializers.ReadOnlyField(source='puppy.id')
class Meta:
model = PuppyOrder
fields = ('puppy', 'amount')
class OrderSerializer(serializers.ModelSerializer):
puppies = PuppyOrderSerializer(source='puppyorder_set', many=True)
user = serializers.ReadOnlyField(source='user.username')
total_price = "100.00"
class Meta:
model = Order
fields = ('id', 'total_price', 'puppies', 'date', 'user')
Любая помощь будет высоко ценится!