├── README.md ├── api ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── apps.cpython-39.pyc │ ├── filters.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── serializers.cpython-39.pyc │ ├── urls.cpython-39.pyc │ └── views.cpython-39.pyc ├── admin.py ├── apps.py ├── filters.py ├── migrations │ ├── __init__.py │ └── __pycache__ │ │ └── __init__.cpython-39.pyc ├── models.py ├── serializers.py ├── tests.py ├── urls.py └── views.py ├── core ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── apps.cpython-39.pyc │ ├── models.cpython-39.pyc │ └── serializers.cpython-39.pyc ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-39.pyc │ │ ├── 0002_user_username.cpython-39.pyc │ │ └── __init__.cpython-39.pyc ├── models.py ├── serializers.py ├── tests.py └── views.py ├── db.sqlite3 ├── ecommerce ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── settings.cpython-39.pyc │ ├── urls.cpython-39.pyc │ └── wsgi.cpython-39.pyc ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── img ├── 565-5650281_happy-boy-clipart-can-do-it-png-transparent.png ├── 6-happy-prince-cartoon-clipart.jpg └── 6-happy-prince-cartoon-clipart_YMW4ali.jpg ├── manage.py ├── requirements.txt └── storeapp ├── __init__.py ├── __pycache__ ├── __init__.cpython-39.pyc ├── admin.cpython-39.pyc ├── apps.cpython-39.pyc └── models.cpython-39.pyc ├── admin.py ├── apps.py ├── migrations ├── 0001_initial.py ├── __init__.py └── __pycache__ │ ├── 0001_initial.cpython-39.pyc │ ├── 0002_alter_product_id.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── models.py ├── tests.py └── views.py /README.md: -------------------------------------------------------------------------------- 1 | # DRF_Tutorial 2 | Building a restful api for ecommerce web application, this is the source code for the 1st episode. 3 | -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__init__.py -------------------------------------------------------------------------------- /api/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/filters.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/filters.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/serializers.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/serializers.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /api/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /api/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /api/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApiConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'api' 7 | -------------------------------------------------------------------------------- /api/filters.py: -------------------------------------------------------------------------------- 1 | from django_filters.rest_framework import FilterSet 2 | from storeapp.models import Product 3 | 4 | 5 | class ProductFilter(FilterSet): 6 | class Meta: 7 | model = Product 8 | fields = { 9 | 'category_id': ['exact'], 10 | 'price': ['gt', 'lt'] 11 | } -------------------------------------------------------------------------------- /api/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/migrations/__init__.py -------------------------------------------------------------------------------- /api/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/api/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /api/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /api/serializers.py: -------------------------------------------------------------------------------- 1 | from importlib.resources import read_binary 2 | from itertools import product 3 | from django.db import transaction 4 | from rest_framework import serializers 5 | from storeapp.models import * 6 | 7 | 8 | class CategorySerializer(serializers.ModelSerializer): 9 | class Meta: 10 | model = Category 11 | fields = ["category_id", "title", "slug"] 12 | 13 | 14 | class ProductSerializer(serializers.ModelSerializer): 15 | class Meta: 16 | model = Product 17 | fields = [ "id", "name", "description", "category", "slug", "inventory", "price"] 18 | 19 | category = CategorySerializer() 20 | 21 | class ReviewSerializer(serializers.ModelSerializer): 22 | class Meta: 23 | model = Review 24 | fields = ["id", "date_created", "name", "description"] 25 | 26 | def create(self, validated_data): 27 | product_id = self.context["product_id"] 28 | return Review.objects.create(product_id = product_id, **validated_data) 29 | 30 | 31 | class SimpleProductSerializer(serializers.ModelSerializer): 32 | class Meta: 33 | model = Product 34 | fields = ["id","name", "price"] 35 | 36 | 37 | 38 | 39 | class CartItemSerializer(serializers.ModelSerializer): 40 | product = SimpleProductSerializer(many=False) 41 | sub_total = serializers.SerializerMethodField( method_name="total") 42 | class Meta: 43 | model= Cartitems 44 | fields = ["id", "cart", "product", "quantity", "sub_total"] 45 | 46 | 47 | def total(self, cartitem:Cartitems): 48 | return cartitem.quantity * cartitem.product.price 49 | 50 | 51 | class AddCartItemSerializer(serializers.ModelSerializer): 52 | product_id = serializers.UUIDField() 53 | 54 | def validate_product_id(self, value): 55 | if not Product.objects.filter(pk=value).exists(): 56 | raise serializers.ValidationError("There is no product associated with the given ID") 57 | 58 | return value 59 | 60 | def save(self, **kwargs): 61 | cart_id = self.context["cart_id"] 62 | product_id = self.validated_data["product_id"] 63 | quantity = self.validated_data["quantity"] 64 | 65 | try: 66 | cartitem = Cartitems.objects.get(product_id=product_id, cart_id=cart_id) 67 | cartitem.quantity += quantity 68 | cartitem.save() 69 | 70 | self.instance = cartitem 71 | 72 | 73 | except: 74 | 75 | self.instance = Cartitems.objects.create(cart_id=cart_id, **self.validated_data) 76 | 77 | return self.instance 78 | 79 | 80 | class Meta: 81 | model = Cartitems 82 | fields = ["id", "product_id", "quantity"] 83 | 84 | 85 | 86 | 87 | 88 | class UpdateCartItemSerializer(serializers.ModelSerializer): 89 | # id = serializers.IntegerField(read_only=True) 90 | class Meta: 91 | model = Cartitems 92 | fields = ["quantity"] 93 | 94 | 95 | class CartSerializer(serializers.ModelSerializer): 96 | id = serializers.UUIDField(read_only=True) 97 | items = CartItemSerializer(many=True, read_only=True) 98 | grand_total = serializers.SerializerMethodField(method_name='main_total') 99 | 100 | class Meta: 101 | model = Cart 102 | fields = ["id", "items", "grand_total"] 103 | 104 | 105 | 106 | def main_total(self, cart: Cart): 107 | items = cart.items.all() 108 | total = sum([item.quantity * item.product.price for item in items]) 109 | return total 110 | 111 | 112 | class OrderItemSerializer(serializers.ModelSerializer): 113 | product = SimpleProductSerializer() 114 | class Meta: 115 | model = OrderItem 116 | fields = ["id", "product", "quantity"] 117 | 118 | 119 | 120 | class OrderSerializer(serializers.ModelSerializer): 121 | items = OrderItemSerializer(many=True, read_only=True) 122 | class Meta: 123 | model = Order 124 | fields = ['id', "placed_at", "pending_status", "owner", "items"] 125 | 126 | 127 | 128 | 129 | class CreateOrderSerializer(serializers.Serializer): 130 | cart_id = serializers.UUIDField() 131 | 132 | 133 | 134 | def validate_cart_id(self, cart_id): 135 | if not Cart.objects.filter(pk=cart_id).exists(): 136 | raise serializers.ValidationError("This cart_id is invalid") 137 | 138 | elif not Cartitems.objects.filter(cart_id=cart_id).exists(): 139 | raise serializers.ValidationError("Sorry your cart is empty") 140 | 141 | return cart_id 142 | 143 | 144 | 145 | def save(self, **kwargs): 146 | with transaction.atomic(): 147 | cart_id = self.validated_data["cart_id"] 148 | user_id = self.context["user_id"] 149 | order = Order.objects.create(owner_id = user_id) 150 | cartitems = Cartitems.objects.filter(cart_id=cart_id) 151 | orderitems = [ 152 | OrderItem(order=order, 153 | product=item.product, 154 | quantity=item.quantity 155 | ) 156 | for item in cartitems 157 | ] 158 | OrderItem.objects.bulk_create(orderitems) 159 | # Cart.objects.filter(id=cart_id).delete() 160 | return order 161 | 162 | 163 | class UpdateOrderSerializer(serializers.ModelSerializer): 164 | class Meta: 165 | model = Order 166 | fields = ["pending_status"] 167 | 168 | class ProfileSerializer(serializers.ModelSerializer): 169 | class Meta: 170 | model = Profile 171 | fields = ["id", "name", 'bio', "picture"] -------------------------------------------------------------------------------- /api/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from . import views 3 | 4 | from rest_framework.routers import DefaultRouter 5 | from rest_framework_nested import routers 6 | 7 | 8 | router = routers.DefaultRouter() 9 | 10 | router.register("products", views.ProductsViewSet) 11 | router.register("categories", views.CategoryViewSet) 12 | router.register("carts", views.CartViewSet) 13 | router.register("n_profiles", views.ProfileViewSet) 14 | router.register("orders", views.OrderViewSet, basename="orders") 15 | 16 | 17 | product_router = routers.NestedDefaultRouter(router, "products", lookup="product") 18 | product_router.register("reviews", views.ReviewViewSet, basename="product-reviews") 19 | 20 | 21 | cart_router = routers.NestedDefaultRouter(router, "carts", lookup="cart") 22 | cart_router.register("items", views.CartItemViewSet, basename="cart-items") 23 | 24 | 25 | 26 | urlpatterns = [ 27 | path("", include(router.urls)), 28 | path("", include(product_router.urls)), 29 | path("", include(cart_router.urls)) 30 | # path("products", views.ApiProducts.as_view()), 31 | # path("products/", views.ApiProduct.as_view()), 32 | # path("categories", views.APICategories.as_view()), 33 | # path("categories/", views.APICategory.as_view()) 34 | ] -------------------------------------------------------------------------------- /api/views.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | from urllib import response 3 | from django.shortcuts import render, get_object_or_404 4 | from api.filters import ProductFilter 5 | from rest_framework.decorators import api_view 6 | from .serializers import * 7 | from storeapp.models import * 8 | from django_filters.rest_framework import DjangoFilterBackend 9 | from rest_framework.response import Response 10 | from rest_framework import status 11 | from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, DestroyModelMixin 12 | from rest_framework.viewsets import ModelViewSet, GenericViewSet 13 | from rest_framework.filters import SearchFilter, OrderingFilter 14 | from rest_framework.pagination import PageNumberPagination 15 | from rest_framework.parsers import MultiPartParser, FormParser 16 | from rest_framework.permissions import IsAuthenticated, IsAdminUser 17 | 18 | 19 | 20 | from api import serializers 21 | 22 | # Create your views here. 23 | class ProductsViewSet(ModelViewSet): 24 | queryset = Product.objects.all() 25 | serializer_class = ProductSerializer 26 | 27 | 28 | filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] 29 | filterset_class = ProductFilter 30 | search_fields = ['name', 'description'] 31 | ordering_fields = ['old_price'] 32 | pagination_class = PageNumberPagination 33 | 34 | 35 | 36 | class CategoryViewSet(ModelViewSet): 37 | queryset = Category.objects.all() 38 | serializer_class = CategorySerializer 39 | 40 | 41 | class ReviewViewSet(ModelViewSet): 42 | serializer_class = ReviewSerializer 43 | 44 | def get_queryset(self): 45 | return Review.objects.filter(product_id=self.kwargs["product_pk"]) 46 | 47 | def get_serializer_context(self): 48 | return {"product_id": self.kwargs["product_pk"]} 49 | 8 50 | 51 | 52 | 53 | class CartViewSet(CreateModelMixin,RetrieveModelMixin, DestroyModelMixin, GenericViewSet): 54 | queryset = Cart.objects.all() 55 | serializer_class = CartSerializer 56 | 57 | 58 | class CartItemViewSet(ModelViewSet): 59 | 60 | http_method_names = ["get", "post", "patch", "delete"] 61 | 62 | def get_queryset(self): 63 | return Cartitems.objects.filter(cart_id=self.kwargs["cart_pk"]) 64 | 65 | 66 | def get_serializer_class(self): 67 | if self.request.method == "POST": 68 | return AddCartItemSerializer 69 | 70 | elif self.request.method == 'PATCH': 71 | return UpdateCartItemSerializer 72 | 73 | return CartItemSerializer 74 | 75 | def get_serializer_context(self): 76 | return {"cart_id": self.kwargs["cart_pk"]} 77 | 78 | 79 | 80 | class OrderViewSet(ModelViewSet): 81 | 82 | http_method_names = ["get", "patch", "post", "delete", "options", "head"] 83 | 84 | def get_permissions(self): 85 | if self.request.method in ["PATCH", "DELETE"]: 86 | return [IsAdminUser()] 87 | return [IsAuthenticated()] 88 | 89 | 90 | 91 | def create(self, request, *args, **kwargs): 92 | serializer = CreateOrderSerializer(data=request.data, context={"user_id": self.request.user.id}) 93 | serializer.is_valid(raise_exception=True) 94 | order = serializer.save() 95 | serializer = OrderSerializer(order) 96 | return Response(serializer.data) 97 | 98 | 99 | 100 | 101 | 102 | 103 | def get_serializer_class(self): 104 | if self.request.method == 'POST': 105 | return CreateOrderSerializer 106 | elif self.request.method == 'PATCH': 107 | return UpdateOrderSerializer 108 | return OrderSerializer 109 | 110 | 111 | def get_queryset(self): 112 | user = self.request.user 113 | if user.is_staff: 114 | return Order.objects.all() 115 | return Order.objects.filter(owner=user) 116 | 117 | # def get_serializer_context(self): 118 | # return {"user_id": self.request.user.id} 119 | 120 | 121 | 122 | 123 | 124 | class ProfileViewSet(ModelViewSet): 125 | queryset = Profile.objects.all() 126 | serializer_class = ProfileSerializer 127 | parser_classes = (MultiPartParser, FormParser) 128 | 129 | def create(self, request, *args, **kwargs): 130 | name = request.data["name"] 131 | bio = request.data["bio"] 132 | picture = request.data["picture"] 133 | 134 | Profile.objects.create(name = name, bio = bio, picture=picture) 135 | 136 | 137 | return Response("Profile created successfully", status=status.HTTP_200_OK) -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/__init__.py -------------------------------------------------------------------------------- /core/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/serializers.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/__pycache__/serializers.cpython-39.pyc -------------------------------------------------------------------------------- /core/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.contrib import admin 3 | from django.contrib.auth.admin import UserAdmin 4 | # from django.utils.translation import ugettext_lazy as _ 5 | from django.contrib.auth import get_user_model 6 | 7 | 8 | class CustomUserAdmin(UserAdmin): 9 | """Define admin model for custom User model with no username field.""" 10 | # fieldsets = ( 11 | # (None, {'fields': ('email', 'password')}), 12 | # (_('Personal info'), {'fields': ('first_name', 'last_name')}), 13 | # (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 14 | # 'groups', 'user_permissions')}), 15 | # (_('Important dates'), {'fields': ('last_login', 'date_joined')}), 16 | # ) 17 | add_fieldsets = ( 18 | (None, { 19 | 'classes': ('wide',), 20 | 'fields': ( 'first_name', 'last_name', 'email', 'password1', 'password2'), 21 | }), 22 | ) 23 | list_display = ('email', 'first_name', 'last_name', 'is_staff') 24 | search_fields = ('email', 'first_name', 'last_name') 25 | ordering = ('email',) 26 | 27 | 28 | admin.site.register(get_user_model(), CustomUserAdmin) -------------------------------------------------------------------------------- /core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CoreConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'core' 7 | -------------------------------------------------------------------------------- /core/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.5 on 2023-05-25 06:36 2 | 3 | from django.db import migrations, models 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('auth', '0012_alter_user_first_name_max_length'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='User', 18 | fields=[ 19 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('password', models.CharField(max_length=128, verbose_name='password')), 21 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 22 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 23 | ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), 24 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), 25 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 26 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), 27 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 28 | ('email', models.EmailField(max_length=254, unique=True)), 29 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), 30 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), 31 | ], 32 | options={ 33 | 'verbose_name': 'user', 34 | 'verbose_name_plural': 'users', 35 | 'abstract': False, 36 | }, 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /core/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/migrations/__init__.py -------------------------------------------------------------------------------- /core/migrations/__pycache__/0001_initial.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/migrations/__pycache__/0001_initial.cpython-39.pyc -------------------------------------------------------------------------------- /core/migrations/__pycache__/0002_user_username.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/migrations/__pycache__/0002_user_username.cpython-39.pyc -------------------------------------------------------------------------------- /core/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/core/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/models.py: -------------------------------------------------------------------------------- 1 | import email 2 | from django.db import models 3 | from django.contrib.auth.models import AbstractUser, BaseUserManager 4 | # Create your models here. 5 | 6 | class UserManager(BaseUserManager): 7 | """Define a model manager for User model with no username field.""" 8 | 9 | def _create_user(self, email, password=None, **extra_fields): 10 | """Create and save a User with the given email and password.""" 11 | if not email: 12 | raise ValueError('The given email must be set') 13 | email = self.normalize_email(email) 14 | user = self.model(email=email, **extra_fields) 15 | user.set_password(password) 16 | user.save(using=self._db) 17 | return user 18 | 19 | def create_user(self, email, password=None, **extra_fields): 20 | extra_fields.setdefault('is_staff', False) 21 | extra_fields.setdefault('is_superuser', False) 22 | return self._create_user(email, password, **extra_fields) 23 | 24 | def create_superuser(self, email, password=None, **extra_fields): 25 | """Create and save a SuperUser with the given email and password.""" 26 | extra_fields.setdefault('is_staff', True) 27 | extra_fields.setdefault('is_superuser', True) 28 | 29 | if extra_fields.get('is_staff') is not True: 30 | raise ValueError('Superuser must have is_staff=True.') 31 | if extra_fields.get('is_superuser') is not True: 32 | raise ValueError('Superuser must have is_superuser=True.') 33 | 34 | return self._create_user(email, password, **extra_fields) 35 | 36 | 37 | class User(AbstractUser): 38 | username = None 39 | email = models.EmailField(unique=True) 40 | 41 | 42 | USERNAME_FIELD = 'email' 43 | REQUIRED_FIELDS = [] 44 | 45 | objects = UserManager() -------------------------------------------------------------------------------- /core/serializers.py: -------------------------------------------------------------------------------- 1 | from djoser.serializers import UserCreateSerializer 2 | 3 | 4 | class MyUserCreateSerializer(UserCreateSerializer): 5 | class Meta(UserCreateSerializer.Meta): 6 | fields = ["id", "email", "first_name", "last_name", "password", "username"] 7 | -------------------------------------------------------------------------------- /core/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /core/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/db.sqlite3 -------------------------------------------------------------------------------- /ecommerce/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/ecommerce/__init__.py -------------------------------------------------------------------------------- /ecommerce/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/ecommerce/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /ecommerce/__pycache__/settings.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/ecommerce/__pycache__/settings.cpython-39.pyc -------------------------------------------------------------------------------- /ecommerce/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/ecommerce/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /ecommerce/__pycache__/wsgi.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/ecommerce/__pycache__/wsgi.cpython-39.pyc -------------------------------------------------------------------------------- /ecommerce/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for ecommerce project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ecommerce.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /ecommerce/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for ecommerce project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.8. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | import os 15 | from datetime import timedelta 16 | 17 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 18 | BASE_DIR = Path(__file__).resolve().parent.parent 19 | 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | SECRET_KEY = "_e)op=dl#c3o=yf=z0_8@)nqb*@a!d5z2&7%1sv8^pp76qlbsu" 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = True 29 | 30 | ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'my-shoppit.herokuapp.com'] 31 | 32 | 33 | # Application definition 34 | 35 | INSTALLED_APPS = [ 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | 'storeapp', 43 | 'core', 44 | 'api', 45 | 'rest_framework', 46 | 'django_filters', 47 | 'djoser' 48 | ] 49 | 50 | MIDDLEWARE = [ 51 | 'django.middleware.security.SecurityMiddleware', 52 | 'whitenoise.middleware.WhiteNoiseMiddleware', 53 | 'django.contrib.sessions.middleware.SessionMiddleware', 54 | 'django.middleware.common.CommonMiddleware', 55 | 'django.middleware.csrf.CsrfViewMiddleware', 56 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 57 | 'django.contrib.messages.middleware.MessageMiddleware', 58 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 59 | ] 60 | 61 | ROOT_URLCONF = 'ecommerce.urls' 62 | 63 | TEMPLATES = [ 64 | { 65 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 66 | 'DIRS': [], 67 | 'APP_DIRS': True, 68 | 'OPTIONS': { 69 | 'context_processors': [ 70 | 'django.template.context_processors.debug', 71 | 'django.template.context_processors.request', 72 | 'django.contrib.auth.context_processors.auth', 73 | 'django.contrib.messages.context_processors.messages', 74 | 75 | ], 76 | }, 77 | }, 78 | ] 79 | 80 | WSGI_APPLICATION = 'ecommerce.wsgi.application' 81 | 82 | 83 | # Database 84 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 85 | 86 | 87 | 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.sqlite3', 92 | 'NAME': BASE_DIR / 'db.sqlite3', 93 | } 94 | } 95 | 96 | 97 | 98 | 99 | 100 | 101 | # Password validation 102 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 103 | 104 | AUTH_PASSWORD_VALIDATORS = [ 105 | { 106 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 107 | }, 108 | { 109 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 110 | }, 111 | { 112 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 113 | }, 114 | { 115 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 116 | }, 117 | ] 118 | 119 | 120 | # Internationalization 121 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 122 | 123 | LANGUAGE_CODE = 'en-us' 124 | 125 | TIME_ZONE = 'UTC' 126 | 127 | USE_I18N = True 128 | 129 | USE_L10N = True 130 | 131 | USE_TZ = True 132 | 133 | 134 | # Static files (CSS, JavaScript, Images) 135 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 136 | 137 | # STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 138 | STATIC_URL = '/static/' 139 | 140 | STATIC_ROOT = BASE_DIR / "staticfiles" 141 | STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" 142 | 143 | # MEDIA_URL = '/media/' 144 | # MEDIA_ROOT = BASE_DIR/'static' 145 | 146 | # Default primary key field type 147 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 148 | 149 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 150 | AUTH_USER_MODEL = 'core.User' 151 | 152 | 153 | 154 | # REST_FRAMEWORK = { 155 | # 'PAGE_SIZE': 3 156 | # } 157 | 158 | 159 | 160 | AWS_QUERYSTRING_AUTH = False 161 | # AWS_S3_FILE_OVERWRITE = False 162 | # DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' 163 | # AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY') 164 | # AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_KEY') 165 | # AWS_STORAGE_BUCKET_NAME = 'shopit-bucket' 166 | 167 | 168 | REST_FRAMEWORK = { 169 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 170 | 'rest_framework_simplejwt.authentication.JWTAuthentication', 171 | ), 172 | } 173 | 174 | 175 | SIMPLE_JWT = { 176 | 'AUTH_HEADER_TYPES': ('JWT',), 177 | 'ACCESS_TOKEN_LIFETIME': timedelta(days=1), 178 | 'REFRESH_TOKEN_LIFETIME': timedelta(days=2), 179 | } 180 | 181 | 182 | # "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY3MjMxMDM0MywiaWF0IjoxNjcyMTM3NTQzLCJqdGkiOiI4ZTA2ZjFmNTZmMjg0NjdjOGUxYTczMmIwZWM3ODkwZSIsInVzZXJfaWQiOjh9.cmnXNQBWapetuPG2TQpoVNjm6NEvzT7awz-wvjPrPUg", 183 | # "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjcyMjIzOTQzLCJpYXQiOjE2NzIxMzc1NDMsImp0aSI6ImQxYjcxNzBiMjgyNTRlNjg4ZjgwNTM0NGViMTYzYjU5IiwidXNlcl9pZCI6OH0.garu_BNiSM5fB48TRbRMXypgECuSmt4ErveOVsynISQ" 184 | 185 | DJOSER = { 186 | 'SERIALIZERS':{ 187 | 'user_create': "core.serializers.MyUserCreateSerializer" 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /ecommerce/urls.py: -------------------------------------------------------------------------------- 1 | """ecommerce URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | 19 | # this is our root url file 20 | 21 | 22 | urlpatterns = [ 23 | path('admin/', admin.site.urls), 24 | path("api/", include("api.urls")), 25 | path("auth/", include('djoser.urls')), 26 | path("auth/", include('djoser.urls.jwt')), 27 | ] 28 | 29 | -------------------------------------------------------------------------------- /ecommerce/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ecommerce project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ecommerce.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /img/565-5650281_happy-boy-clipart-can-do-it-png-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/img/565-5650281_happy-boy-clipart-can-do-it-png-transparent.png -------------------------------------------------------------------------------- /img/6-happy-prince-cartoon-clipart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/img/6-happy-prince-cartoon-clipart.jpg -------------------------------------------------------------------------------- /img/6-happy-prince-cartoon-clipart_YMW4ali.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/img/6-happy-prince-cartoon-clipart_YMW4ali.jpg -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ecommerce.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.5.2 2 | boto3==1.25.1 3 | botocore==1.28.1 4 | certifi==2022.6.15 5 | cffi==1.15.0 6 | charset-normalizer==2.0.12 7 | coreapi==2.3.3 8 | coreschema==0.0.4 9 | coverage==6.4.1 10 | cryptography==37.0.3 11 | defusedxml==0.7.1 12 | distlib==0.3.6 13 | Django==4.0.5 14 | django-cors-headers==3.13.0 15 | django-debug-toolbar==3.4.0 16 | django-filter==21.1 17 | django-storages==1.13.1 18 | django-templated-mail==1.1.1 19 | djangorestframework==3.13.1 20 | # djangorestframework-simplejwt==5.2.2 21 | djoser==2.1.0 22 | drf-nested-routers==0.93.4 23 | filelock==3.8.0 24 | gunicorn==20.1.0 25 | idna==3.3 26 | itypes==1.2.0 27 | Jinja2==3.1.2 28 | jmespath==1.0.1 29 | MarkupSafe==2.1.1 30 | oauthlib==3.2.0 31 | Pillow==9.1.1 32 | pipenv==2022.10.12 33 | platformdirs==2.5.2 34 | psycopg2==2.9.3 35 | pycparser==2.21 36 | PyJWT==2.4.0 37 | python-dateutil==2.8.2 38 | python3-openid==3.2.0 39 | pytz==2022.1 40 | requests==2.28.0 41 | requests-oauthlib==1.3.1 42 | s3transfer==0.6.0 43 | six==1.16.0 44 | social-auth-app-django==4.0.0 45 | social-auth-core==4.3.0 46 | sqlparse==0.4.2 47 | tzdata==2022.1 48 | uritemplate==4.1.1 49 | urllib3==1.26.9 50 | virtualenv==20.16.5 51 | virtualenv-clone==0.5.7 52 | whitenoise==6.2.0 53 | -------------------------------------------------------------------------------- /storeapp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/__init__.py -------------------------------------------------------------------------------- /storeapp/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/__pycache__/apps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/__pycache__/apps.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import * 3 | # Register your models here. 4 | 5 | class ProductAdmin(admin.ModelAdmin): 6 | prepopulated_fields = {'slug': ('name',)} 7 | 8 | class CategoryAdmin(admin.ModelAdmin): 9 | prepopulated_fields = {'slug': ('title',)} 10 | 11 | admin.site.register(Category, CategoryAdmin) 12 | admin.site.register(Product, ProductAdmin) 13 | admin.site.register(Cart) 14 | admin.site.register(Cartitems) 15 | admin.site.register(Order) 16 | admin.site.register(OrderItem) 17 | 18 | 19 | -------------------------------------------------------------------------------- /storeapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StoreappConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'storeapp' 7 | -------------------------------------------------------------------------------- /storeapp/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.5 on 2023-05-25 06:36 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import uuid 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Cart', 20 | fields=[ 21 | ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), 22 | ('created', models.DateTimeField(auto_now_add=True)), 23 | ], 24 | ), 25 | migrations.CreateModel( 26 | name='Category', 27 | fields=[ 28 | ('title', models.CharField(max_length=200)), 29 | ('category_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), 30 | ('slug', models.SlugField(default=None)), 31 | ('icon', models.CharField(blank=True, default=None, max_length=100, null=True)), 32 | ], 33 | ), 34 | migrations.CreateModel( 35 | name='Order', 36 | fields=[ 37 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 38 | ('placed_at', models.DateTimeField(auto_now_add=True)), 39 | ('pending_status', models.CharField(choices=[('P', 'Pending'), ('C', 'Complete'), ('F', 'Failed')], default='PAYMENT_STATUS_PENDING', max_length=50)), 40 | ('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), 41 | ], 42 | ), 43 | migrations.CreateModel( 44 | name='Product', 45 | fields=[ 46 | ('name', models.CharField(max_length=200)), 47 | ('description', models.TextField(blank=True, null=True)), 48 | ('discount', models.BooleanField(default=False)), 49 | ('image', models.ImageField(blank=True, default='', null=True, upload_to='img')), 50 | ('price', models.FloatField(default=100.0)), 51 | ('slug', models.SlugField(default=None)), 52 | ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), 53 | ('inventory', models.IntegerField(default=5)), 54 | ('top_deal', models.BooleanField(default=False)), 55 | ('flash_sales', models.BooleanField(default=False)), 56 | ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='products', to='storeapp.category')), 57 | ], 58 | ), 59 | migrations.CreateModel( 60 | name='Profile', 61 | fields=[ 62 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 63 | ('name', models.CharField(max_length=30)), 64 | ('bio', models.TextField()), 65 | ('picture', models.ImageField(blank=True, null=True, upload_to='img')), 66 | ], 67 | ), 68 | migrations.CreateModel( 69 | name='Review', 70 | fields=[ 71 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 72 | ('date_created', models.DateTimeField(auto_now_add=True)), 73 | ('description', models.TextField(default='description')), 74 | ('name', models.CharField(max_length=50)), 75 | ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='storeapp.product')), 76 | ], 77 | ), 78 | migrations.CreateModel( 79 | name='OrderItem', 80 | fields=[ 81 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 82 | ('quantity', models.PositiveSmallIntegerField()), 83 | ('order', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='items', to='storeapp.order')), 84 | ('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='storeapp.product')), 85 | ], 86 | ), 87 | migrations.AddField( 88 | model_name='category', 89 | name='featured_product', 90 | field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='featured_product', to='storeapp.product'), 91 | ), 92 | migrations.CreateModel( 93 | name='Cartitems', 94 | fields=[ 95 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 96 | ('quantity', models.PositiveSmallIntegerField(default=0)), 97 | ('cart', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='items', to='storeapp.cart')), 98 | ('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cartitems', to='storeapp.product')), 99 | ], 100 | ), 101 | ] 102 | -------------------------------------------------------------------------------- /storeapp/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/migrations/__init__.py -------------------------------------------------------------------------------- /storeapp/migrations/__pycache__/0001_initial.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/migrations/__pycache__/0001_initial.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/migrations/__pycache__/0002_alter_product_id.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/migrations/__pycache__/0002_alter_product_id.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeWithClinton/DRF_Tutorial/43c3f9360fdb11e2b551c8e360f6d01b6ecc1417/storeapp/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /storeapp/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | import uuid 3 | from django.conf import settings 4 | 5 | 6 | # Create your models here. 7 | 8 | 9 | class Category(models.Model): 10 | title = models.CharField(max_length=200) 11 | category_id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, unique=True) 12 | slug = models.SlugField(default= None) 13 | featured_product = models.OneToOneField('Product', on_delete=models.CASCADE, blank=True, null=True, related_name='featured_product') 14 | icon = models.CharField(max_length=100, default=None, blank = True, null=True) 15 | 16 | def __str__(self): 17 | return self.title 18 | 19 | 20 | 21 | class Review(models.Model): 22 | product = models.ForeignKey("Product", on_delete=models.CASCADE, related_name = "reviews") 23 | date_created = models.DateTimeField(auto_now_add=True) 24 | description = models.TextField(default="description") 25 | name = models.CharField(max_length=50) 26 | 27 | def __str__(self): 28 | return self.description 29 | 30 | 31 | 32 | class Product(models.Model): 33 | name = models.CharField(max_length=200) 34 | description = models.TextField(blank=True, null=True) 35 | discount = models. BooleanField(default=False) 36 | image = models.ImageField(upload_to = 'img', blank = True, null=True, default='') 37 | price = models.FloatField(default=100.00) 38 | category = models.ForeignKey(Category, on_delete=models.SET_NULL, blank=True, null=True, related_name='products') 39 | slug = models.SlugField(default=None) 40 | id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, unique=True) 41 | inventory = models.IntegerField(default=5) 42 | top_deal=models.BooleanField(default=False) 43 | flash_sales = models.BooleanField(default=False) 44 | 45 | def __str__(self): 46 | return self.name 47 | 48 | 49 | class Cart(models.Model): 50 | id = models.UUIDField(default=uuid.uuid4, primary_key=True) 51 | created = models.DateTimeField(auto_now_add=True) 52 | 53 | def __str__(self): 54 | return str(self.id) 55 | 56 | class Cartitems(models.Model): 57 | cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name="items", null=True, blank=True) 58 | product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True, related_name='cartitems') 59 | quantity = models.PositiveSmallIntegerField(default=0) 60 | 61 | 62 | 63 | class Order(models.Model): 64 | 65 | 66 | PAYMENT_STATUS_PENDING = 'P' 67 | PAYMENT_STATUS_COMPLETE = 'C' 68 | PAYMENT_STATUS_FAILED = 'F' 69 | 70 | PAYMENT_STATUS_CHOICES = [ 71 | (PAYMENT_STATUS_PENDING, 'Pending'), 72 | (PAYMENT_STATUS_COMPLETE, 'Complete'), 73 | (PAYMENT_STATUS_FAILED, 'Failed'), 74 | ] 75 | placed_at = models.DateTimeField(auto_now_add=True) 76 | pending_status = models.CharField( 77 | max_length=50, choices=PAYMENT_STATUS_CHOICES, default='PAYMENT_STATUS_PENDING') 78 | owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT) 79 | 80 | def __str__(self): 81 | return self.pending_status 82 | 83 | 84 | 85 | class OrderItem(models.Model): 86 | order = models.ForeignKey(Order, on_delete=models.PROTECT, related_name = "items") 87 | product = models.ForeignKey(Product, on_delete=models.PROTECT) 88 | quantity = models.PositiveSmallIntegerField() 89 | 90 | 91 | def __str__(self): 92 | return self.product.name 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | class Profile(models.Model): 104 | name = models.CharField(max_length=30) 105 | bio = models.TextField() 106 | picture = models.ImageField(upload_to = 'img', blank=True, null=True) 107 | 108 | def __str__(self): 109 | return self.name 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | # class SavedItem(models.Model): 122 | # owner = models.ForeignKey(Customer, on_delete=models.CASCADE, null = True, blank=True) 123 | # product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True) 124 | # added = models.IntegerField(default=0) 125 | 126 | 127 | 128 | # def __str__(self): 129 | # return str(self.id) 130 | 131 | -------------------------------------------------------------------------------- /storeapp/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /storeapp/views.py: -------------------------------------------------------------------------------- 1 | # Create your views here. 2 | 3 | --------------------------------------------------------------------------------