From fe02a1e8a8b6324b1f569bdbcfa9947b9e470b69 Mon Sep 17 00:00:00 2001 From: Abdullah-Alsalhi Date: Sun, 31 Jul 2022 22:33:14 +0300 Subject: [PATCH 1/2] build eCommerce project with brand and products apps --- .gitignore | 2 + brand/__init__.py | 0 brand/admin.py | 3 + brand/apps.py | 6 ++ brand/migrations/0001_initial.py | 24 ++++++ brand/migrations/__init__.py | 0 brand/models.py | 10 +++ brand/serializers.py | 8 ++ brand/tests.py | 3 + brand/urls.py | 11 +++ brand/views.py | 65 +++++++++++++++ db.sqlite3 | Bin 0 -> 143360 bytes eCommerce/__init__.py | 0 eCommerce/asgi.py | 16 ++++ eCommerce/settings.py | 126 +++++++++++++++++++++++++++++ eCommerce/urls.py | 23 ++++++ eCommerce/wsgi.py | 16 ++++ manage.py | 22 +++++ product/__init__.py | 0 product/admin.py | 3 + product/apps.py | 6 ++ product/migrations/0001_initial.py | 29 +++++++ product/migrations/__init__.py | 0 product/models.py | 14 ++++ product/serializers.py | 9 +++ product/tests.py | 3 + product/urls.py | 11 +++ product/views.py | 58 +++++++++++++ requirements.txt | 5 ++ 29 files changed, 473 insertions(+) create mode 100644 .gitignore create mode 100644 brand/__init__.py create mode 100644 brand/admin.py create mode 100644 brand/apps.py create mode 100644 brand/migrations/0001_initial.py create mode 100644 brand/migrations/__init__.py create mode 100644 brand/models.py create mode 100644 brand/serializers.py create mode 100644 brand/tests.py create mode 100644 brand/urls.py create mode 100644 brand/views.py create mode 100644 db.sqlite3 create mode 100644 eCommerce/__init__.py create mode 100644 eCommerce/asgi.py create mode 100644 eCommerce/settings.py create mode 100644 eCommerce/urls.py create mode 100644 eCommerce/wsgi.py create mode 100755 manage.py create mode 100644 product/__init__.py create mode 100644 product/admin.py create mode 100644 product/apps.py create mode 100644 product/migrations/0001_initial.py create mode 100644 product/migrations/__init__.py create mode 100644 product/models.py create mode 100644 product/serializers.py create mode 100644 product/tests.py create mode 100644 product/urls.py create mode 100644 product/views.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d75edeae --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv +__pycache__ \ No newline at end of file diff --git a/brand/__init__.py b/brand/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/brand/admin.py b/brand/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/brand/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/brand/apps.py b/brand/apps.py new file mode 100644 index 00000000..cb0a8d86 --- /dev/null +++ b/brand/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BrandConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'brand' diff --git a/brand/migrations/0001_initial.py b/brand/migrations/0001_initial.py new file mode 100644 index 00000000..0ac08cb0 --- /dev/null +++ b/brand/migrations/0001_initial.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.6 on 2022-07-31 17:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Brand', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=32)), + ('description', models.TextField()), + ('established_at', models.DateTimeField()), + ('city', models.CharField(max_length=128)), + ], + ), + ] diff --git a/brand/migrations/__init__.py b/brand/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/brand/models.py b/brand/models.py new file mode 100644 index 00000000..8a08a5f0 --- /dev/null +++ b/brand/models.py @@ -0,0 +1,10 @@ +from django.db import models + +# Create your models here. + +class Brand(models.Model): + + title = models.CharField(max_length=32, unique=True) + description = models.TextField() + established_at = models.DateTimeField(auto_now=True) + city = models.CharField(max_length=128) \ No newline at end of file diff --git a/brand/serializers.py b/brand/serializers.py new file mode 100644 index 00000000..fa8a6706 --- /dev/null +++ b/brand/serializers.py @@ -0,0 +1,8 @@ +from rest_framework import serializers +from .models import Brand + +class BrandSerilizer(serializers.ModelSerializer): + + class Meta: + model = Brand + fields = '__all__' \ No newline at end of file diff --git a/brand/tests.py b/brand/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/brand/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/brand/urls.py b/brand/urls.py new file mode 100644 index 00000000..dd10a473 --- /dev/null +++ b/brand/urls.py @@ -0,0 +1,11 @@ +from django.urls import path +from . import views + +app_name = "brand" + +urlpatterns = [ + path("add/", views.add_brand, name="add_brand"), + path("all/", views.get_brands, name="all_brands"), + path("update/", views.update_brand, name="update_brand"), + path("delete/", views.delete_brand, name="delete_brand"), +] \ No newline at end of file diff --git a/brand/views.py b/brand/views.py new file mode 100644 index 00000000..2aa7204b --- /dev/null +++ b/brand/views.py @@ -0,0 +1,65 @@ +# from django.shortcuts import render + +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework import status +from brand.models import Brand +from .serializers import BrandSerilizer +# Create your views here. + + +@api_view(['POST']) +def add_brand(request: Request) -> Response: + + brand = BrandSerilizer(data=request.data) + + if brand.is_valid(): + brand.save() + return Response({"msg" : "added succefully!"}) + return Response({"msg": brand.errors}) + +@api_view(['GET']) +def get_brands(request: Request) -> Response: + + if "max" and "min" in request.query_params: + + maximumm = int(request.query_params.get("max")) + minmumm = int(request.query_params.get("min")) + + brands = Brand.objects.all()[minmumm:maximumm] + + elif "search" in request.query_params: + print("went") + brand_title = request.query_params.get("search") + brands = Brand.objects.filter(title=brand_title) + + else: + + brands = Brand.objects.order_by('-id').all() + + data = BrandSerilizer(brands, many=True).data + + return Response(data, status=status.HTTP_200_OK) + + +@api_view(["PUT"]) +def update_brand(request: Request, brand_id) -> Response: + + brand = Brand.objects.get(id=brand_id) + + data = BrandSerilizer(instance=brand, data=request.data,partial=True) + + if data.is_valid(): + data.save() + return Response({"msg": "updated succefully"}, status=status.HTTP_201_CREATED) + + +@api_view(["DELETE"]) +def delete_brand(request: Request, brand_id) -> Response: + + brand = Brand.objects.get(id=brand_id) + + brand.delete() + + return Response({"msg":"brand deleted succefully"}) \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..095648b3a9d1bae1fe62e6abbcfa58aa3b44561c GIT binary patch literal 143360 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", views.update_product, name="update_product"), + path("delete/", views.delete_product, name="delete_product"), +] \ No newline at end of file diff --git a/product/views.py b/product/views.py new file mode 100644 index 00000000..b2fca006 --- /dev/null +++ b/product/views.py @@ -0,0 +1,58 @@ +# from django.shortcuts import render +from rest_framework.decorators import api_view +from rest_framework.request import Request +from rest_framework.response import Response +from .serializers import ProductSerilizer +from rest_framework import status +from .models import Product +# Create your views here. + + +@api_view(["POST"]) +def add_product(request: Request) -> Response: + + product = ProductSerilizer(data=request.data) + + if product.is_valid(): + product.save() + return Response({"msg" : "added succefully!"}) + return Response({"msg": product.errors}) + + +@api_view(['GET']) +def get_products(request: Request) -> Response: + + + + if "brand" in request.query_params : + + brand_id = int(request.query_params.get("brand")) + products = Product.objects.filter(brand=brand_id) + data = ProductSerilizer(products, many=True).data + + else: + products = Product.objects.order_by('-id').all() + data = ProductSerilizer(products, many=True).data + + return Response(data, status=status.HTTP_200_OK) + + +@api_view(["PUT"]) +def update_product(request: Request, product_id) -> Response: + + product = Product.objects.get(id=product_id) + + data = ProductSerilizer(instance=product, data=request.data,partial=True) + + if data.is_valid(): + data.save() + return Response({"msg": "updated succefully"}, status=status.HTTP_201_CREATED) + +@api_view(["DELETE"]) +def delete_product(request: Request, product_id) -> Response: + + product = Product.objects.get(id=product_id) + + product.delete() + + return Response({"msg":"product deleted succefully"}) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..ff453381 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +asgiref==3.5.2 +Django==4.0.6 +djangorestframework==3.13.1 +pytz==2022.1 +sqlparse==0.4.2 From 39e973edae971b0c30cde60e660daa4cf514b68f Mon Sep 17 00:00:00 2001 From: Abdullah-Alsalhi Date: Sun, 31 Jul 2022 22:37:35 +0300 Subject: [PATCH 2/2] schema migrations --- ..._brand_established_at_alter_brand_title.py | 23 ++++++++++++++++++ db.sqlite3 | Bin 143360 -> 151552 bytes .../0002_alter_product_is_active.py | 18 ++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 brand/migrations/0002_alter_brand_established_at_alter_brand_title.py create mode 100644 product/migrations/0002_alter_product_is_active.py diff --git a/brand/migrations/0002_alter_brand_established_at_alter_brand_title.py b/brand/migrations/0002_alter_brand_established_at_alter_brand_title.py new file mode 100644 index 00000000..d92cc0b8 --- /dev/null +++ b/brand/migrations/0002_alter_brand_established_at_alter_brand_title.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-07-31 19:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('brand', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='brand', + name='established_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='brand', + name='title', + field=models.CharField(max_length=32, unique=True), + ), + ] diff --git a/db.sqlite3 b/db.sqlite3 index 095648b3a9d1bae1fe62e6abbcfa58aa3b44561c..41157abfb83f7b02cee710aec9a52d074ecfa61f 100644 GIT binary patch delta 592 zcmZp8z|pXPbAq&>DFXw8DiA9GF(VNBPt-AHG~Jl6gr8ZA%YQPvfF=vqWG?@WjnZ88 zPGYPK(yopLMfoYE$t4B`21fCTIVGt@@lcWY%;NaOH>tL`N}kVL@hXMwsKEG#kIbaq`v3X2*9HeFzupe4lA z%fMyBxsu~9hY;HHeXiscZXKrS-ogR?D zsKux5O@E!hC_B9+iP3(#TN0xj zk3y)QXJDwSCVv`(=fp4^D2M_?UZmmWD delta 311 zcmZozz}fJCV}i7xF#`jGG7!Un>qH%6M&peMOZb^ZxL!?W7tq|;xQlD^D=9tJjg1!k z;=+8)+KdH7`6;EzCGk+2jh}aNy8aACkxd5X`HUqK8*OlK>;{X2yd5@|!NOOi&YK@MYk#;atgamqUo{6`Kfa zF4K4BZsr3_M;Na%`10rR74U2F-kjK|%-qasI$boIQEU3zd`6Dx?%9kFrZ?s=N=#SD zVT|I|Y|JrX7gtthY?hzCB!@9;dTuVG^z^maj0)4Wa~bW~H4Tl~#9ig5PfTW%UH&|Y yk%NUljp@_I#&=BHZ{{*iXJj;+UYO5l!>F)*T|Q$_!=wV1%`6N4$S*1o03rYx+gzCd diff --git a/product/migrations/0002_alter_product_is_active.py b/product/migrations/0002_alter_product_is_active.py new file mode 100644 index 00000000..f03a337f --- /dev/null +++ b/product/migrations/0002_alter_product_is_active.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.6 on 2022-07-31 19:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='product', + name='is_active', + field=models.BooleanField(default=True), + ), + ]