Как сохранить несколько объектов в базу данных в представлениях django rest framework

Итак, я пытаюсь добавить новый продукт в мою базу данных, используя django's restapi. но продукт может содержать несколько категорий, которые связаны через третью много-ко-многим модель и дополнительные изображения, которые являются внешними ключами к продукту

вот мой models.py

class Products(models.Model):
    product_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=35, null=False, unique=True)
    description = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2, default=0.)
    main_image = models.FileField(upload_to='shop/images')
    created_on = models.DateTimeField(blank=True, default=datetime.now)

class Category(models.Model):
    category_id = models.AutoField(primary_key=True)
    category = models.CharField(max_length=20, null=True, blank=True)
    created_on = models.DateTimeField(blank=True, default=datetime.now)

    class Meta:
        db_table = 'Category'

class ProductsCategory(models.Model):
    productscategory_id = models.AutoField(primary_key=True)
    category = models.ForeignKey(to=Category, on_delete=models.CASCADE)
    product = models.ForeignKey(to=Products, on_delete=models.CASCADE)
    created_on = models.DateTimeField(blank=True, default=datetime.now)

    class Meta:
        db_table = 'ProductsCategory'

class Pictures(models.Model):
    picture_id = models.AutoField(primary_key=True)
    image = models.FileField(upload_to='shop/images')
    product = models.ForeignKey(to=Products, on_delete=models.CASCADE)
    created_on = models.DateTimeField(blank=True, default=datetime.now)

    class Meta:
        db_table = 'Pictures'

и вот что я попробовал:

@api_view(['POST'])
@permission_classes([IsModerator])
def create_product(request):
    product_details = ProductsSerializer(request.POST, request.FILES)
    pictures = PicturesSerializer(request.POST, request.FILES, many=True)
    category_list = request.POST.getlist("category")

    if product_details.is_valid() and validate_file_extension(request.FILES.get("main_image")):
        try:
            product = product_details.save()
            if len(category_list) > 0:
                for i in category_list:
                    if check_category(i):
                        category = Category.objects.get(category=i)
                        ProductsCategory.objects.create(category=category, product=product)
                    else:
                        category = Category.objects.create(category=i)
                        ProductsCategory.objects.create(category=category, product=product)
            if pictures:
                for image in request.FILES.getlist("image"):
                    if validate_file_extension(image):
                        Pictures.objects.create(image=image, product=product)
                    else:
                        error = {"error": "invalid extra pictures extension"}
                        return Response(error)
            return Response((product_details.data, pictures.data, category_list), status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response(e)
    else:
        return Response((product_details._errors, pictures._errors), status=status.HTTP_400_BAD_REQUEST)

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

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

Я предлагаю вам изменить структуру models.py на следующую:

from django.db import models

class Category(models.Model):
    category = models.CharField(max_length=20, null=True, blank=True)
    created_on = models.DateTimeField(auto_now=True)
    
    class Meta:
        verbose_name_plural  =  "Categories"

class Picture(models.Model):
    image = models.FileField(upload_to='shop/images')
    product = models.ForeignKey(to=Products, on_delete=models.CASCADE)
    created_on = models.DateTimeField(blank=True, default=datetime.now)
    
class Product(models.Model):
    name = models.CharField(max_length=35, null=False, unique=True)
    description = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2, default=0.)
    main_image = models.FileField(upload_to='shop/images')
    more_images = models.ManyToManyField(Pictures, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now=True)

Затем в своем serializer.py добавьте:

from rest_framework import serializers
from .models import Category, Picture, Product

class CategorySerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Category
        fields = "__all__"

class PictureSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Picture
        fields = "__all__"

class ProductSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Product
        fields = "__all__"

В вашем views я предлагаю использовать ViewSets: views.py

from .models import Category, Picture, Product
from .serializer import CategorySerializer, PictureSerializer, ProductSerializer
from rest_framework import viewsets
# import custom permissions if any

class CategoryViewSet(viewsets.ModelViewSet):
    
    serializer_class = CategorySerializer
    queryset = Category.objects.all()

class PictureViewSet(viewsets.ModelViewSet):
    
    serializer_class = PictureSerializer
    queryset = Picture.objects.all()

class ProductViewSet(viewsets.ModelViewSet):
    
    serializer_class = ProductSerializer
    queryset = Product.objects.all()
    permission_classes = [IsModerator]

В вашем приложении urls.py добавьте маршрутизатор для ваших наборов представлений, и он автоматически создаст пути для ваших представлений:

from django.urls import path
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'category', views.CategoryViewSet, basename='category')
router.register(r'picture', views.PictureViewSet, basename='picture')
router.register(r'product', views.ProductViewSet, basename='product')

urlpatterns = [
    path('', include(router.urls)),
]

Журнал изменений:

  • Вам не нужно добавлять поле ID в каждую модель, Django делает это за вас. Если только это не особый случай.
  • Ваши таблицы базы данных по умолчанию называются по имени вашей модели. Так что нет необходимости указывать и это.
  • Я упростил структуру ваших моделей, чтобы сделать ее более чистой. Но она по-прежнему делает то, что вы хотите.
  • Django добавляет s для создания множественного имени для каждой модели. Поэтому вы можете называть ее в единственном числе, если не нужно уточнять. Например, categories.
  • .
  • Наборы представлений сократят вашу работу, предоставляя вам действия по составлению списков и извлечению информации.

Для доступа к конкретному экземпляру, например, продукта, достаточно добавить /<product id> после конечной точки листинга и создания продукта.

Примечание: Вы должны добавить id без скобок.

Я также предлагаю вам пройти это руководство DRF. Это улучшит ваше понимание Django REST framework.

Вернуться на верх