From 4f45b97aaaba1a87bc78c48000eb7ad228229db7 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Fri, 29 Aug 2025 16:34:15 +0500 Subject: [PATCH] add: order model, order create api, order create serializer, order item model --- config/conf/cors.py | 4 +- core/apps/orders/admin/__init__.py | 1 + core/apps/orders/admin/order.py | 14 ++++++ core/apps/orders/apps.py | 3 ++ core/apps/orders/migrations/0001_initial.py | 45 +++++++++++++++++++ .../migrations/0002_orderitem_product.py | 20 +++++++++ core/apps/orders/models/__init__.py | 1 + core/apps/orders/models/order.py | 31 +++++++++++++ core/apps/orders/serializers/order.py | 45 +++++++++++++++++++ core/apps/orders/urls.py | 3 +- core/apps/orders/views/order.py | 28 ++++++++++++ 11 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 core/apps/orders/admin/order.py create mode 100644 core/apps/orders/migrations/0001_initial.py create mode 100644 core/apps/orders/migrations/0002_orderitem_product.py create mode 100644 core/apps/orders/models/order.py create mode 100644 core/apps/orders/serializers/order.py create mode 100644 core/apps/orders/views/order.py diff --git a/config/conf/cors.py b/config/conf/cors.py index b177aa2..86e0987 100644 --- a/config/conf/cors.py +++ b/config/conf/cors.py @@ -4,7 +4,7 @@ CORS_ALLOWED_ORIGINS = [ ] CSRF_TRUSTED_ORIGINS = [ - 'http://localhost:8001', - 'http://127.0.0.1:8001', + 'http://localhost:8080', + 'http://127.0.0.1:8080', 'https://horeca.felixits.uz', ] \ No newline at end of file diff --git a/core/apps/orders/admin/__init__.py b/core/apps/orders/admin/__init__.py index e69de29..5c48881 100644 --- a/core/apps/orders/admin/__init__.py +++ b/core/apps/orders/admin/__init__.py @@ -0,0 +1 @@ +from .order import * \ No newline at end of file diff --git a/core/apps/orders/admin/order.py b/core/apps/orders/admin/order.py new file mode 100644 index 0000000..f232762 --- /dev/null +++ b/core/apps/orders/admin/order.py @@ -0,0 +1,14 @@ +from django.contrib import admin + +from core.apps.orders.models.order import Order, OrderItem + + +class OrderItemInline(admin.TabularInline): + model = OrderItem + extra = 0 + + +@admin.register(Order) +class OrderAdmin(admin.ModelAdmin): + list_display = ['id', 'user', 'total_price'] + inlines = [OrderItemInline] \ No newline at end of file diff --git a/core/apps/orders/apps.py b/core/apps/orders/apps.py index 2d18476..da81335 100644 --- a/core/apps/orders/apps.py +++ b/core/apps/orders/apps.py @@ -4,3 +4,6 @@ from django.apps import AppConfig class OrdersConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'core.apps.orders' + + def ready(self): + from . import admin \ No newline at end of file diff --git a/core/apps/orders/migrations/0001_initial.py b/core/apps/orders/migrations/0001_initial.py new file mode 100644 index 0000000..4ddb8cb --- /dev/null +++ b/core/apps/orders/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 5.2 on 2025-08-29 16:13 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Order', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('total_price', models.PositiveBigIntegerField(default=0)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Buyurtma', + 'verbose_name_plural': 'Buyurtmalar', + }, + ), + migrations.CreateModel( + name='OrderItem', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('quantity', models.PositiveIntegerField()), + ('price', models.PositiveBigIntegerField()), + ('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='orders.order')), + ], + options={ + 'verbose_name': 'Buyurtma elementi', + 'verbose_name_plural': 'Buyurtma elementlari', + }, + ), + ] diff --git a/core/apps/orders/migrations/0002_orderitem_product.py b/core/apps/orders/migrations/0002_orderitem_product.py new file mode 100644 index 0000000..e0c51da --- /dev/null +++ b/core/apps/orders/migrations/0002_orderitem_product.py @@ -0,0 +1,20 @@ +# Generated by Django 5.2 on 2025-08-29 16:17 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('orders', '0001_initial'), + ('products', '0002_category_name_ru_category_name_uz_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='orderitem', + name='product', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='items', to='products.product'), + ), + ] diff --git a/core/apps/orders/models/__init__.py b/core/apps/orders/models/__init__.py index e69de29..5c48881 100644 --- a/core/apps/orders/models/__init__.py +++ b/core/apps/orders/models/__init__.py @@ -0,0 +1 @@ +from .order import * \ No newline at end of file diff --git a/core/apps/orders/models/order.py b/core/apps/orders/models/order.py new file mode 100644 index 0000000..0f1e626 --- /dev/null +++ b/core/apps/orders/models/order.py @@ -0,0 +1,31 @@ +from django.db import models + +from core.apps.shared.models import BaseModel +from core.apps.accounts.models import User +from core.apps.products.models import Product + + +class Order(BaseModel): + total_price = models.PositiveBigIntegerField(default=0) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='orders') + + def __str__(self): + return f'{self.user} order' + + class Meta: + verbose_name = 'Buyurtma' + verbose_name_plural = 'Buyurtmalar' + + +class OrderItem(BaseModel): + order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items') + quantity = models.PositiveIntegerField() + price = models.PositiveBigIntegerField() + product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='items', null=True) + + def __str__(self): + return f'{self.quantity} - {self.price} to {self.order}' + + class Meta: + verbose_name = 'Buyurtma elementi' + verbose_name_plural = 'Buyurtma elementlari' \ No newline at end of file diff --git a/core/apps/orders/serializers/order.py b/core/apps/orders/serializers/order.py new file mode 100644 index 0000000..669a62d --- /dev/null +++ b/core/apps/orders/serializers/order.py @@ -0,0 +1,45 @@ +from django.db import transaction + +from rest_framework import serializers + +from core.apps.orders.models import Order, OrderItem +from core.apps.products.models import Product + + +class OrderItemCreateSerializer(serializers.Serializer): + product_id = serializers.UUIDField() + quantity = serializers.IntegerField() + + def validate(self, data): + product = Product.objects.filter(id=data['product_id']).first() + if not product: + raise serializers.ValidationError("Product not found") + data['product'] = product + data['price'] = product.price * data['quantity'] + return data + + +class OrderCreateSerializer(serializers.Serializer): + items = OrderItemCreateSerializer(many=True) + + def create(self, validated_data): + with transaction.atomic(): + order_items = validated_data.pop('items') + order = Order.objects.create( + user=self.context.get('user'), + ) + items = [] + total_price = 0 + for item in order_items: + items.append(OrderItem( + product=item.get('product'), + price=item.get('price'), + quantity=item.get('quantity'), + order=order, + )) + total_price += item.get('price') + OrderItem.objects.bulk_create(items) + order.total_price = total_price + order.save() + return order + \ No newline at end of file diff --git a/core/apps/orders/urls.py b/core/apps/orders/urls.py index c9dc166..cdbec43 100644 --- a/core/apps/orders/urls.py +++ b/core/apps/orders/urls.py @@ -1,6 +1,7 @@ from django.urls import path, include +from core.apps.orders.views import order as order_views urlpatterns = [ - + path('order/create/', order_views.OrderCreateApiView.as_view()), ] \ No newline at end of file diff --git a/core/apps/orders/views/order.py b/core/apps/orders/views/order.py new file mode 100644 index 0000000..af5e228 --- /dev/null +++ b/core/apps/orders/views/order.py @@ -0,0 +1,28 @@ +from rest_framework import generics, permissions +from rest_framework.response import Response + +from core.apps.orders.models import Order, OrderItem +from core.apps.orders.serializers import order as serializers + + +class OrderCreateApiView(generics.GenericAPIView): + serializer_class = serializers.OrderCreateSerializer + queryset = Order.objects.all() + permission_classes = [permissions.IsAuthenticated] + + def post(self, request): + serializer = self.serializer_class(data=request.data, context={'user': request.user}) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response( + {'success': True, 'message': 'Firdavs aka order create qilindi, tekshirib koring'}, + status=200 + ) + return Response( + { + 'success': False, + "message": "Firdavs aka order create qilishda xatolik chiqdi, errorni oqib koring", + 'error': serializer.errors, + }, + status=400 + ) \ No newline at end of file