├── .gitignore
├── Procfile
├── README.md
├── api
├── __init__.py
├── admin.py
├── apps.py
├── category
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20201107_1405.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── order
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── payment
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── product
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── tests.py
├── urls.py
├── user
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
└── views.py
├── db.json
├── ecommerce
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
├── manage.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98 | __pypackages__/
99 |
100 | # Celery stuff
101 | celerybeat-schedule
102 | celerybeat.pid
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 |
134 | # pytype static type analyzer
135 | .pytype/
136 |
137 | # Cython debug symbols
138 | cython_debug/
139 | .vscode
140 | TODO
141 | SPEC.md
142 | SQL.md
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn ecommerce.wsgi
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Ecommerce Rest API
2 |
3 |
4 |
5 | An Ecommerce Store Backend to Sell Products. It accepts Paypal/Stripe Payment. Built with Python/Django Rest Framework.
6 |
7 |
8 | ## Table of Contents
9 |
10 | - [Introduction](#introduction)
11 | - [Features](#features)
12 | - [Installation Process](#installation-process)
13 | - [Project Demo](#project-demo)
14 | - [Feedback](#feedback)
15 |
16 | ## Introduction
17 |
18 | DRF-Ecommerce-API provides API endpoints to Sell Physical Products through Paypal/Stripe Payment. Built with Python/Django and 100% free to use.
19 |
20 | ## Features
21 |
22 | A few of the things you can do with this app:
23 |
24 | * Admin can create/update/delete Product Category
25 | * Admin can create/update/delete Product Detail
26 | * Authenticated Users can make POST requests to Product Category & Product Detail
27 | * Unauthenticated Users can only make GET requests to Product Category & Product Detail
28 | * Users can SignUp to be authorized
29 | * Authorized Users can make Payment & Order Products
30 |
31 | ## Installation Process
32 |
33 | **Installation Process (Windows)**
34 |
35 | 1. Create a Virtual Environment `virtualenv projectenv`
36 | 2. Go To environment Directory `cd projectenv/scripts`
37 | 3. Activate Virtual Environment `activate`
38 | 4. Clone This Project `git clone https://github.com/mahmud-sajib/DRF-Ecommerce-API.git`
39 | 5. Go To Project Directory `cd DRF-Ecommerce-API`
40 | 6. Install Required Package `pip install -r requirements.txt`
41 | 7. Migrate Database `python manage.py migrate`
42 | 8. Finally Run The Project `python manage.py runserver`
43 |
44 | ## Project Demo
45 |
46 | ### Live Demo
47 |
48 | Live Project url: [ecom-rest.herokuapp.com](https://ecom-rest.herokuapp.com/)
49 |
50 | ### API Documentation Page
51 |
52 |
53 |
54 |
55 |
56 | ## Feedback
57 |
58 | Feel free to [file an issue](https://github.com/mahmud-sajib/DRF-Ecommerce-API/issues/new). If you wish to contribute, please feel free to do so!
59 |
60 |
--------------------------------------------------------------------------------
/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/__init__.py
--------------------------------------------------------------------------------
/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 | name = 'api'
6 |
--------------------------------------------------------------------------------
/api/category/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/category/__init__.py
--------------------------------------------------------------------------------
/api/category/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import Category
3 |
4 | # Register your models here.
5 |
6 | admin.site.register(Category)
7 |
--------------------------------------------------------------------------------
/api/category/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CategoryConfig(AppConfig):
5 | name = 'category'
6 |
--------------------------------------------------------------------------------
/api/category/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.8 on 2020-11-07 05:26
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | initial = True
9 |
10 | dependencies = [
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='Category',
16 | fields=[
17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18 | ('name', models.CharField(max_length=50)),
19 | ('description', models.CharField(max_length=250)),
20 | ('created_at', models.DateTimeField(auto_now_add=True)),
21 | ('updated_at', models.DateTimeField(auto_now=True)),
22 | ],
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/api/category/migrations/0002_auto_20201107_1405.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.8 on 2020-11-07 08:05
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('category', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelOptions(
14 | name='category',
15 | options={'verbose_name_plural': 'Categories'},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/api/category/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/category/migrations/__init__.py
--------------------------------------------------------------------------------
/api/category/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
5 | class Category(models.Model):
6 | name = models.CharField(max_length=50)
7 | description = models.CharField(max_length=250)
8 | created_at = models.DateTimeField(auto_now_add=True)
9 | updated_at = models.DateTimeField(auto_now=True)
10 |
11 | def __str__(self):
12 | return f"{self.name}"
13 |
14 | class Meta:
15 | verbose_name_plural="Categories"
16 |
17 |
18 |
--------------------------------------------------------------------------------
/api/category/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from .models import Category
4 |
5 | class CategorySerializer(serializers.ModelSerializer):
6 | class Meta:
7 | # Model to be serialized
8 | model = Category
9 | # Fields to be serialized
10 | fields = ('name', 'description')
--------------------------------------------------------------------------------
/api/category/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/api/category/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework import routers
2 | from django.urls import path, include
3 | from . import views
4 |
5 | router = routers.DefaultRouter()
6 | router.register(r'', views.CategoryViewSet)
7 |
8 | urlpatterns = [
9 | path('', include(router.urls)),
10 | ]
11 |
--------------------------------------------------------------------------------
/api/category/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 | from .serializers import CategorySerializer
3 | from .models import Category
4 |
5 | # Create your views here.
6 | class CategoryViewSet(viewsets.ModelViewSet):
7 | # Operations to be performed
8 | queryset = Category.objects.all().order_by('-created_at')
9 | # Class responsible for serializing the data
10 | serializer_class = CategorySerializer
--------------------------------------------------------------------------------
/api/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | from django.db import migrations
2 | from api.user.models import CustomUser
3 |
4 | class Migration(migrations.Migration):
5 | def seed_data(apps, schema_editor):
6 | user = CustomUser(name="mahmud", email="sajibforest@gmail.com", is_staff=True, is_superuser=True, phone="01553848755", gender="Male")
7 |
8 | user.set_password("123456")
9 |
10 | user.save()
11 |
12 | dependencies = [
13 |
14 | ]
15 |
16 | operations = [
17 | migrations.RunPython(seed_data)
18 | ]
--------------------------------------------------------------------------------
/api/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/migrations/__init__.py
--------------------------------------------------------------------------------
/api/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/api/order/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/order/__init__.py
--------------------------------------------------------------------------------
/api/order/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import Order
3 |
4 | # Register your models here.
5 | admin.site.register(Order)
6 |
--------------------------------------------------------------------------------
/api/order/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class OrderConfig(AppConfig):
5 | name = 'order'
6 |
--------------------------------------------------------------------------------
/api/order/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.8 on 2020-11-10 10:54
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import django.db.models.deletion
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='Order',
19 | fields=[
20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('product_names', models.CharField(max_length=150)),
22 | ('total_products', models.CharField(default=0, max_length=250)),
23 | ('total_amount', models.CharField(default=0, max_length=250)),
24 | ('created_at', models.DateTimeField(auto_now_add=True)),
25 | ('updated_at', models.DateTimeField(auto_now=True)),
26 | ('transaction_id', models.CharField(default=0, max_length=150)),
27 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
28 | ],
29 | ),
30 | ]
31 |
--------------------------------------------------------------------------------
/api/order/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/order/migrations/__init__.py
--------------------------------------------------------------------------------
/api/order/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from api.user.models import CustomUser
3 | from api.product.models import Product
4 |
5 | # Create your models here.
6 |
7 | class Order(models.Model):
8 | user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
9 | product_names = models.CharField(max_length=150)
10 | total_products = models.CharField(max_length=250, default=0)
11 | total_amount = models.CharField(max_length=250, default=0)
12 | created_at = models.DateTimeField(auto_now_add=True)
13 | updated_at = models.DateTimeField(auto_now=True)
14 | transaction_id = models.CharField(max_length=150, default=0)
15 |
16 | def __str__(self):
17 | return f"{self.product_name}"
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/api/order/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from .models import Order
4 |
5 | class OrderSerializer(serializers.ModelSerializer):
6 |
7 | class Meta:
8 | # Model to be serialized
9 | model = Order
10 | # Fields to be serialized
11 | fields = ('user',)
--------------------------------------------------------------------------------
/api/order/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/api/order/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework import routers
2 | from django.urls import path, include
3 | from . import views
4 |
5 | router = routers.DefaultRouter()
6 | router.register(r'', views.OrderViewSet)
7 |
8 | urlpatterns = [
9 | path('add-order///', views.add_order, name='add-order'),
10 | path('', include(router.urls)),
11 | ]
12 |
--------------------------------------------------------------------------------
/api/order/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 | from .serializers import OrderSerializer
3 | from .models import Order
4 | from django.http import JsonResponse
5 | from django.contrib.auth import get_user_model
6 | from django.views.decorators.csrf import csrf_exempt
7 |
8 |
9 | # User Authentication view
10 | def validate_user_session(id, token):
11 | """Allow ordering for only authenticated users"""
12 | UserModel = get_user_model()
13 |
14 | try:
15 | user = UserModel.objects.get(pk=id)
16 |
17 | # Check if Session Token matches User Token
18 | if user.session_token == token:
19 | return True # User is authenticated
20 | else:
21 | return False # User is unauthenticated
22 |
23 | except UserModel.DoesNotExist:
24 | return False
25 |
26 |
27 | # Add Order view
28 | def add_order(request, id, token):
29 | if not validate_user_session(id, token):
30 | return JsonResponse({'error':'Please login again', 'code':'1'})
31 |
32 | if request.method == "POST":
33 | user_id = id
34 | transaction_id = request.POST['transaction_id']
35 | amount = request.POST['amount']
36 | products = request.POST['products']
37 | total_no_products = len(products.split(',')[:-1])
38 |
39 | UserModel = get_user_model()
40 |
41 | try:
42 | user = UserModel.objects.get(pk=user_id)
43 |
44 | except UserModel.DoesNotExist:
45 | return JsonResponse({'error':'User does not exist'})
46 |
47 | order_detail = Order(user=user, product_names=products, total_products=total_no_products, total_amount=amount, transaction_id=transaction_id)
48 |
49 | order_detail.save()
50 |
51 | return JsonResponse({'success':True, 'error':False, 'msg':'Order placed successfully'})
52 |
53 | # Order View
54 | class OrderViewSet(viewsets.ModelViewSet):
55 | # Operations to be performed
56 | queryset = Order.objects.all().order_by('id')
57 | # Class responsible for serializing the data
58 | serializer_class = OrderSerializer
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/api/payment/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/payment/__init__.py
--------------------------------------------------------------------------------
/api/payment/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/api/payment/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class PaymentConfig(AppConfig):
5 | name = 'payment'
6 |
--------------------------------------------------------------------------------
/api/payment/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/payment/migrations/__init__.py
--------------------------------------------------------------------------------
/api/payment/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/api/payment/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/api/payment/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path, include
2 | from . import views
3 |
4 | urlpatterns = [
5 | path('generate-token///', views.generate_token, name='generate-token'),
6 | path('process-payment///', views.process_payment, name='process-payment'),
7 | ]
8 |
--------------------------------------------------------------------------------
/api/payment/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.http import HttpResponse, JsonResponse
3 | from django.contrib.auth.decorators import login_required
4 | from django.contrib.auth import get_user_model
5 | from django.views.decorators.csrf import csrf_exempt
6 |
7 | import braintree
8 |
9 | # Create your views here.
10 |
11 | # BrainTree Credentials
12 | gateway = braintree.BraintreeGateway(
13 | braintree.Configuration(
14 | braintree.Environment.Sandbox,
15 | merchant_id="4ymx8dm8hyz2x6rt",
16 | public_key="6wt4d62db8rfsy7b",
17 | private_key="4741def360e584d5141d06e9b0f64dfc"
18 | )
19 | )
20 |
21 | # User Authentication view
22 | def validate_user_session(id, token):
23 | """Allow payment completion for only authenticated users"""
24 | UserModel = get_user_model()
25 |
26 | try:
27 | user = UserModel.objects.get(pk=id)
28 |
29 | # Check if Session Token matches User Token
30 | if user.session_token == token:
31 | return True # User is authenticated
32 | else:
33 | return False # User is unauthenticated
34 |
35 | except UserModel.DoesNotExist:
36 | return False
37 |
38 | # Generate Payment Token view
39 | @csrf_exempt
40 | def generate_token(request, id, token):
41 | if not validate_user_session(id, token):
42 | return JsonResponse({'error':'Inavlid Session. Please login again'})
43 |
44 | # Generate token if user is authenticated
45 | return JsonResponse({'clientToken':gateway.client_token.generate(), 'success':True})
46 |
47 | # Process Payment view
48 | @csrf_exempt
49 | def process_payment(request, id, token):
50 | if not validate_user_session(id, token):
51 | return JsonResponse({'error':'Inavlid Session. Please login again'})
52 |
53 | # Get the payment nonce from client
54 | nonce_from_the_client = request.POST["paymentMethodNonce"]
55 | # Get the amount from client
56 | amount_from_the_client = request.POST["amount"]
57 |
58 | # Process the payment
59 | result = gateway.transaction.sale({
60 | "amount": amount_from_the_client,
61 | "payment_method_nonce": nonce_from_the_client,
62 | "options": {
63 | "submit_for_settlement": True
64 | }
65 | })
66 |
67 | # Post payment results
68 | if result.is_success:
69 | return JsonResponse({
70 | 'success':result.is_success,
71 | 'transaction':{
72 | 'id':result.transaction.id,
73 | 'amount':result.transaction.amount
74 | }
75 | })
76 | else:
77 | return JsonResponse({'error':True, 'success':False})
78 |
79 |
80 |
--------------------------------------------------------------------------------
/api/product/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/product/__init__.py
--------------------------------------------------------------------------------
/api/product/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import Product
3 |
4 | # Register your models here.
5 | admin.site.register(Product)
6 |
--------------------------------------------------------------------------------
/api/product/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ProductConfig(AppConfig):
5 | name = 'product'
6 |
--------------------------------------------------------------------------------
/api/product/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.8 on 2020-11-07 08:05
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | initial = True
10 |
11 | dependencies = [
12 | ('category', '0002_auto_20201107_1405'),
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='Product',
18 | fields=[
19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20 | ('name', models.CharField(max_length=50)),
21 | ('description', models.CharField(max_length=250)),
22 | ('created_at', models.DateTimeField(auto_now_add=True)),
23 | ('updated_at', models.DateTimeField(auto_now=True)),
24 | ('price', models.CharField(max_length=50)),
25 | ('stock', models.CharField(max_length=50)),
26 | ('image', models.ImageField(blank=True, null=True, upload_to='products/%Y/%m/%d')),
27 | ('is_active', models.BooleanField(default=True)),
28 | ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='category.Category')),
29 | ],
30 | ),
31 | ]
32 |
--------------------------------------------------------------------------------
/api/product/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/product/migrations/__init__.py
--------------------------------------------------------------------------------
/api/product/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from api.category.models import Category
3 |
4 | # Create your models here.
5 |
6 | class Product(models.Model):
7 | name = models.CharField(max_length=50)
8 | description = models.CharField(max_length=250)
9 | created_at = models.DateTimeField(auto_now_add=True)
10 | updated_at = models.DateTimeField(auto_now=True)
11 | price = models.CharField(max_length=50)
12 | stock = models.CharField(max_length=50)
13 | image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True, null=True)
14 | is_active = models.BooleanField(default=True)
15 | category = models.ForeignKey(Category, on_delete=models.SET_NULL, blank=True, null=True)
16 |
17 | def __str__(self):
18 | return f"{self.name}"
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/api/product/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from .models import Product
4 |
5 | class ProductSerializer(serializers.ModelSerializer):
6 | # Get the image url by serializing `ImageField`
7 | image = serializers.ImageField(max_length=None, allow_empty_file=False, allow_null=True, required=False)
8 |
9 | class Meta:
10 | # Model to be serialized
11 | model = Product
12 | # Fields to be serialized
13 | fields = ('id', 'name', 'description', 'price', 'stock', 'image', 'category')
--------------------------------------------------------------------------------
/api/product/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/api/product/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework import routers
2 | from django.urls import path, include
3 | from . import views
4 |
5 | router = routers.DefaultRouter()
6 | router.register(r'', views.ProductViewSet)
7 |
8 | urlpatterns = [
9 | path('', include(router.urls)),
10 | ]
11 |
--------------------------------------------------------------------------------
/api/product/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 | from .serializers import ProductSerializer
3 | from .models import Product
4 |
5 | # Create your views here.
6 |
7 | # Product View
8 | class ProductViewSet(viewsets.ModelViewSet):
9 | # Operations to be performed
10 | queryset = Product.objects.all().order_by('id')
11 | # Class responsible for serializing the data
12 | serializer_class = ProductSerializer
13 |
--------------------------------------------------------------------------------
/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 |
3 |
4 |
5 | # from rest_framework.authtoken import views
6 |
7 | from api import views
8 |
9 | urlpatterns = [
10 | path('', views.home, name="home"),
11 | path('category/', include('api.category.urls')),
12 | path('product/', include('api.product.urls')),
13 | path('user/', include('api.user.urls')),
14 | path('order/', include('api.order.urls')),
15 | path('payment/', include('api.payment.urls')),
16 | ]
--------------------------------------------------------------------------------
/api/user/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/user/__init__.py
--------------------------------------------------------------------------------
/api/user/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import CustomUser
3 |
4 | # Register your models here.
5 | admin.site.register(CustomUser)
6 |
--------------------------------------------------------------------------------
/api/user/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class UserConfig(AppConfig):
5 | name = 'user'
6 |
--------------------------------------------------------------------------------
/api/user/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.8 on 2020-11-10 05:48
2 |
3 | import django.contrib.auth.models
4 | from django.db import migrations, models
5 | import django.utils.timezone
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ('auth', '0011_update_proxy_permissions'),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='CustomUser',
19 | fields=[
20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 | ('password', models.CharField(max_length=128, verbose_name='password')),
22 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
23 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
24 | ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
25 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
26 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
27 | ('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')),
28 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
29 | ('name', models.CharField(default='Anonymous', max_length=50)),
30 | ('email', models.EmailField(max_length=254, unique=True)),
31 | ('phone', models.CharField(blank=True, max_length=20, null=True)),
32 | ('gender', models.CharField(blank=True, max_length=10, null=True)),
33 | ('session_token', models.CharField(default=0, max_length=10)),
34 | ('created_at', models.DateTimeField(auto_now_add=True)),
35 | ('updated_at', models.DateTimeField(auto_now=True)),
36 | ('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')),
37 | ('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')),
38 | ],
39 | options={
40 | 'verbose_name': 'user',
41 | 'verbose_name_plural': 'users',
42 | 'abstract': False,
43 | },
44 | managers=[
45 | ('objects', django.contrib.auth.models.UserManager()),
46 | ],
47 | ),
48 | ]
49 |
--------------------------------------------------------------------------------
/api/user/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/api/user/migrations/__init__.py
--------------------------------------------------------------------------------
/api/user/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import AbstractUser
3 |
4 | # Create your models here.
5 |
6 |
7 | class CustomUser(AbstractUser):
8 |
9 | name = models.CharField(max_length=50, default='Anonymous')
10 | email = models.EmailField(max_length=254, unique=True)
11 | username = None
12 |
13 | USERNAME_FIELD = 'email'
14 | REQUIRED_FIELDS = []
15 |
16 | phone = models.CharField(max_length=20, blank=True, null=True)
17 | gender = models.CharField(max_length=10, blank=True, null=True)
18 | session_token = models.CharField(max_length=10, default=0)
19 | created_at = models.DateTimeField(auto_now_add=True)
20 | updated_at = models.DateTimeField(auto_now=True)
21 |
--------------------------------------------------------------------------------
/api/user/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from django.contrib.auth.hashers import make_password
3 | from rest_framework.decorators import authentication_classes, permission_classes
4 |
5 | from .models import CustomUser
6 |
7 | class UserSerializer(serializers.ModelSerializer):
8 |
9 | # Create User
10 | def create(self, validated_data):
11 | # Extract the password
12 | password = validated_data.pop('password', None)
13 |
14 | # Assign `CustomUser` model's data to `instance` object
15 | instance = self.Meta.model(**validated_data)
16 |
17 | if password is not None:
18 | instance.set_password(password)
19 |
20 | instance.save()
21 | return instance
22 |
23 | # Update User
24 | def update(self, instance, validated_data):
25 | for attr, value in validated_data.items():
26 | if attr == 'password':
27 | instance.set_password(value) # Apply `set_password` function
28 | else:
29 | setattr(instance, attr, value) # Update the instance with new value
30 |
31 | instance.save()
32 | return instance
33 |
34 | class Meta:
35 | # Model to be serialized
36 | model = CustomUser
37 |
38 | # Fields to be serialized
39 | fields = ('name', 'email', 'password', 'phone', 'gender', 'is_active', 'is_staff', 'is_superuser')
40 |
41 | # Make the password inaccessible in GET request and don't show in plain text
42 | extra_kwargs = {
43 | 'password':{
44 | 'write_only':True,
45 | 'style':{'input_type':'password'}
46 | }
47 | }
--------------------------------------------------------------------------------
/api/user/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/api/user/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework import routers
2 | from django.urls import path, include
3 | from . import views
4 |
5 | router = routers.DefaultRouter()
6 | router.register(r'', views.UserViewSet)
7 |
8 | urlpatterns = [
9 | path('login/', views.signin, name='signin'),
10 | path('logout//', views.signout, name='signout'),
11 | path('', include(router.urls)),
12 | ]
13 |
--------------------------------------------------------------------------------
/api/user/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 | from rest_framework.permissions import AllowAny
3 | from .serializers import UserSerializer
4 | from .models import CustomUser
5 | from django.http import JsonResponse
6 | from django.contrib.auth import get_user_model
7 | from django.views.decorators.csrf import csrf_exempt
8 | from django.contrib.auth import login, logout
9 |
10 | import random
11 | import re
12 |
13 | # Create your views here.
14 |
15 | # Generate session view
16 | def generate_session_token(length=10):
17 | char_list = [chr(i) for i in range(97, 123)]
18 | int_list = [str(i) for i in range(10)]
19 |
20 | # Create a unique token
21 | return ''.join(random.SystemRandom().choice(char_list + int_list) for _ in range(length))
22 |
23 | # Login view
24 | @csrf_exempt # Allow CSRF
25 | def signin(request):
26 | if not request.method == 'POST':
27 | return JsonResponse({'error':"You are not eligible for login"})
28 |
29 | username = request.POST['email']
30 | password = request.POST['password']
31 |
32 | if not re.match("^[\w\.\+\-]+\@[\w]+\.[a-z]{2,3}$", username):
33 | return JsonResponse({'error':"Enter a valid Email"})
34 |
35 | if len(password) < 6:
36 | return JsonResponse({'error':"Password must be 6 character long"})
37 |
38 | UserModel = get_user_model()
39 |
40 | try:
41 | user = UserModel.objects.get(email=username)
42 |
43 | if user.check_password(password):
44 | usr_dict = UserModel.objects.filter(email=username).values().first()
45 | usr_dict.pop('password') # Extract Password so it doesn't travel to frontend
46 |
47 | # If session_token is not 0 it's already running (user is logged in)
48 | if user.session_token != '0':
49 | # If user is not logged in we set session_token to 0
50 | user.session_token = '0'
51 | # Save session
52 | user.save()
53 | return JsonResponse({'error':"Previous session exists"})
54 |
55 | # Generate session token
56 | token = generate_session_token()
57 | user.session_token = token
58 | # Save session
59 | user.save()
60 | # Log user in
61 | login (request, user)
62 | # Return session token along with user attributes
63 | return JsonResponse({'token': token, 'user': usr_dict})
64 | else:
65 | return JsonResponse({'token': 'Invalid password'})
66 |
67 | except UserModel.DoesNotExist:
68 | return JsonResponse({'error': 'Invalid Email'})
69 |
70 | # Logout view
71 | def signout(request, id):
72 |
73 | UserModel = get_user_model()
74 |
75 | try:
76 | user = UserModel.objects.get(pk=id)
77 | user.session_token = "0"
78 | user.save()
79 | logout(request)
80 |
81 | except UserModel.DoesNotExist:
82 | return JsonResponse({'error': 'Invalid User ID'})
83 |
84 | return JsonResponse({'success': 'Logout successful'})
85 |
86 | # User Permission View
87 | class UserViewSet(viewsets.ModelViewSet):
88 | permission_classes_by_action = {'create' : [AllowAny]}
89 | queryset = CustomUser.objects.all().order_by('id')
90 | serializer_class = UserSerializer
91 |
92 | def get_permissions(self):
93 | try:
94 | # Return permission_classes depending on `action`
95 | return [permission() for permission in self.permission_classes_by_action[self.action]]
96 |
97 | except KeyError:
98 | # If action is not set return default permission_classes
99 | return [permission() for permission in self.permission_classes]
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/api/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.http import JsonResponse
3 |
4 |
5 | # Create your views here.
6 |
7 | def home(request):
8 | return JsonResponse({'info':"Django React Ecommerce Project", 'developer':"Mahmud Sajib"})
9 |
10 |
11 |
--------------------------------------------------------------------------------
/db.json:
--------------------------------------------------------------------------------
1 | [{"model": "auth.permission", "pk": 1, "fields": {"name": "Can add log entry", "content_type": 1, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change log entry", "content_type": 1, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete log entry", "content_type": 1, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can view log entry", "content_type": 1, "codename": "view_logentry"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can add permission", "content_type": 2, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can change permission", "content_type": 2, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can delete permission", "content_type": 2, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can view permission", "content_type": 2, "codename": "view_permission"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can add group", "content_type": 3, "codename": "add_group"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can change group", "content_type": 3, "codename": "change_group"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can delete group", "content_type": 3, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can view group", "content_type": 3, "codename": "view_group"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add content type", "content_type": 4, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change content type", "content_type": 4, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete content type", "content_type": 4, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can view content type", "content_type": 4, "codename": "view_contenttype"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can add session", "content_type": 5, "codename": "add_session"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can change session", "content_type": 5, "codename": "change_session"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can delete session", "content_type": 5, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can view session", "content_type": 5, "codename": "view_session"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can add Token", "content_type": 6, "codename": "add_token"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can change Token", "content_type": 6, "codename": "change_token"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can delete Token", "content_type": 6, "codename": "delete_token"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can view Token", "content_type": 6, "codename": "view_token"}}, {"model": "auth.permission", "pk": 25, "fields": {"name": "Can add token", "content_type": 7, "codename": "add_tokenproxy"}}, {"model": "auth.permission", "pk": 26, "fields": {"name": "Can change token", "content_type": 7, "codename": "change_tokenproxy"}}, {"model": "auth.permission", "pk": 27, "fields": {"name": "Can delete token", "content_type": 7, "codename": "delete_tokenproxy"}}, {"model": "auth.permission", "pk": 28, "fields": {"name": "Can view token", "content_type": 7, "codename": "view_tokenproxy"}}, {"model": "auth.permission", "pk": 29, "fields": {"name": "Can add category", "content_type": 8, "codename": "add_category"}}, {"model": "auth.permission", "pk": 30, "fields": {"name": "Can change category", "content_type": 8, "codename": "change_category"}}, {"model": "auth.permission", "pk": 31, "fields": {"name": "Can delete category", "content_type": 8, "codename": "delete_category"}}, {"model": "auth.permission", "pk": 32, "fields": {"name": "Can view category", "content_type": 8, "codename": "view_category"}}, {"model": "auth.permission", "pk": 33, "fields": {"name": "Can add product", "content_type": 9, "codename": "add_product"}}, {"model": "auth.permission", "pk": 34, "fields": {"name": "Can change product", "content_type": 9, "codename": "change_product"}}, {"model": "auth.permission", "pk": 35, "fields": {"name": "Can delete product", "content_type": 9, "codename": "delete_product"}}, {"model": "auth.permission", "pk": 36, "fields": {"name": "Can view product", "content_type": 9, "codename": "view_product"}}, {"model": "auth.permission", "pk": 37, "fields": {"name": "Can add user", "content_type": 10, "codename": "add_customuser"}}, {"model": "auth.permission", "pk": 38, "fields": {"name": "Can change user", "content_type": 10, "codename": "change_customuser"}}, {"model": "auth.permission", "pk": 39, "fields": {"name": "Can delete user", "content_type": 10, "codename": "delete_customuser"}}, {"model": "auth.permission", "pk": 40, "fields": {"name": "Can view user", "content_type": 10, "codename": "view_customuser"}}, {"model": "auth.permission", "pk": 41, "fields": {"name": "Can add order", "content_type": 11, "codename": "add_order"}}, {"model": "auth.permission", "pk": 42, "fields": {"name": "Can change order", "content_type": 11, "codename": "change_order"}}, {"model": "auth.permission", "pk": 43, "fields": {"name": "Can delete order", "content_type": 11, "codename": "delete_order"}}, {"model": "auth.permission", "pk": 44, "fields": {"name": "Can view order", "content_type": 11, "codename": "view_order"}}, {"model": "sessions.session", "pk": "y9ax7cytjs3z23h6cj3mxf5bblc2v22y", "fields": {"session_data": "OWY3MGFhZTRiZTZlMzgyNmQ4OTRkMjUyOWM4YjA1YTA2NmY3Y2MyZjp7Il9hdXRoX3VzZXJfaWQiOiIxIiwiX2F1dGhfdXNlcl9iYWNrZW5kIjoiZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmQiLCJfYXV0aF91c2VyX2hhc2giOiIwODllNzNmNmYzODQwMGNhYmRlZWIyMzAxNzZjNDJhYjhmNDc2YTYwIn0=", "expire_date": "2020-11-28T05:27:59.543Z"}}, {"model": "user.customuser", "pk": 1, "fields": {"password": "pbkdf2_sha256$180000$qIyUPaJXEaIz$uQJTfpNh6EQ7LfPGIG4F9JSl3gHFXB+6O7mSuLraKSs=", "last_login": "2020-11-14T05:27:59.447Z", "is_superuser": true, "first_name": "", "last_name": "", "is_staff": true, "is_active": true, "date_joined": "2020-11-14T05:26:21.038Z", "name": "mahmud", "email": "sajibforest@gmail.com", "phone": "01553848755", "gender": "Male", "session_token": "0", "created_at": "2020-11-14T05:26:21.546Z", "updated_at": "2020-11-14T05:26:21.546Z", "groups": [], "user_permissions": []}}]
--------------------------------------------------------------------------------
/ecommerce/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mahmud-sajib/Django-Ecommerce-API/36d42f67a08ab626150b6ed7e7e952b0ee68d581/ecommerce/__init__.py
--------------------------------------------------------------------------------
/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.0/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.0.8.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/3.0/ref/settings/
11 | """
12 |
13 | import os
14 | import django_heroku
15 |
16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
18 |
19 |
20 | # Quick-start development settings - unsuitable for production
21 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = '81z2%e(-*1w=561dt195n8+my=fzz5o%=z2811p@ywu0^w7242'
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = True
28 |
29 | ALLOWED_HOSTS = ['ecom-rest.herokuapp.com']
30 |
31 |
32 | # Application definition
33 |
34 | INSTALLED_APPS = [
35 | 'django.contrib.admin',
36 | 'django.contrib.auth',
37 | 'django.contrib.contenttypes',
38 | 'django.contrib.sessions',
39 | 'django.contrib.messages',
40 | 'django.contrib.staticfiles',
41 | 'corsheaders',
42 | 'rest_framework',
43 | 'rest_framework.authtoken',
44 | 'drf_yasg',
45 | 'api',
46 | 'api.category',
47 | 'api.product',
48 | 'api.user',
49 | 'api.order',
50 | 'api.payment',
51 | ]
52 |
53 | MIDDLEWARE = [
54 | 'corsheaders.middleware.CorsMiddleware',
55 | 'django.middleware.security.SecurityMiddleware',
56 | 'django.contrib.sessions.middleware.SessionMiddleware',
57 | 'django.middleware.common.CommonMiddleware',
58 | 'django.middleware.csrf.CsrfViewMiddleware',
59 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
60 | 'django.contrib.messages.middleware.MessageMiddleware',
61 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
62 | ]
63 |
64 | ROOT_URLCONF = 'ecommerce.urls'
65 |
66 | TEMPLATES = [
67 | {
68 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
69 | 'DIRS': [],
70 | 'APP_DIRS': True,
71 | 'OPTIONS': {
72 | 'context_processors': [
73 | 'django.template.context_processors.debug',
74 | 'django.template.context_processors.request',
75 | 'django.contrib.auth.context_processors.auth',
76 | 'django.contrib.messages.context_processors.messages',
77 | ],
78 | },
79 | },
80 | ]
81 |
82 | WSGI_APPLICATION = 'ecommerce.wsgi.application'
83 |
84 |
85 | # Database
86 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
87 |
88 | DATABASES = {
89 | 'default': {
90 | 'ENGINE': 'django.db.backends.sqlite3',
91 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
92 | }
93 | }
94 |
95 |
96 | # Password validation
97 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
98 |
99 | AUTH_PASSWORD_VALIDATORS = [
100 | {
101 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
102 | },
103 | {
104 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
105 | },
106 | {
107 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
108 | },
109 | {
110 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
111 | },
112 | ]
113 |
114 |
115 | # Internationalization
116 | # https://docs.djangoproject.com/en/3.0/topics/i18n/
117 |
118 | LANGUAGE_CODE = 'en-us'
119 |
120 | TIME_ZONE = 'UTC'
121 |
122 | USE_I18N = True
123 |
124 | USE_L10N = True
125 |
126 | USE_TZ = True
127 |
128 |
129 | # Static files (CSS, JavaScript, Images)
130 | # https://docs.djangoproject.com/en/3.0/howto/static-files/
131 |
132 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
133 | STATIC_URL = '/static/'
134 |
135 |
136 | # Location that holds user-uploaded files.
137 | MEDIA_ROOT = os.path.join(BASE_DIR, 'static/images')
138 |
139 | # URL that handles the media files served from MEDIA_ROOT.
140 | MEDIA_URL = '/images/'
141 |
142 | AUTH_USER_MODEL = "user.CustomUser"
143 |
144 | django_heroku.settings(locals())
145 |
146 | # Cors header config:
147 | CORS_ALLOW_ALL_ORIGINS = True
148 |
149 | # REST FRAMEWORK config:
150 | REST_FRAMEWORK = {
151 | # Use Django's standard `django.contrib.auth` permissions,
152 | # or allow read-only access for unauthenticated users.
153 | 'DEFAULT_PERMISSION_CLASSES': [
154 | 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
155 | ],
156 | 'DEFAULT_AUTHENTICATION_CLASSES': [
157 | 'rest_framework.authentication.BasicAuthentication',
158 | 'rest_framework.authentication.SessionAuthentication',
159 | 'rest_framework.authentication.TokenAuthentication',
160 | ]
161 | }
162 |
--------------------------------------------------------------------------------
/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.0/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 | from django.conf.urls.static import static
20 | from django.conf import settings
21 |
22 | from rest_framework import permissions
23 | from drf_yasg.views import get_schema_view
24 | from drf_yasg import openapi
25 |
26 | schema_view = get_schema_view(
27 | openapi.Info(
28 | title="Ecommerce Rest API",
29 | default_version='v1',
30 | description="A Python/Django API to build E-commerce stores!",
31 | # terms_of_service="https://www.google.com/policies/terms/",
32 | # contact=openapi.Contact(email="contact@snippets.local"),
33 | # license=openapi.License(name="BSD License"),
34 | ),
35 | public=True,
36 | permission_classes=(permissions.AllowAny,),
37 | )
38 |
39 |
40 | urlpatterns = [
41 | # path('api-documentation/', schema_view),
42 | path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
43 | path('admin/', admin.site.urls),
44 | path('api-auth/', include('rest_framework.urls')),
45 | path('api/', include('api.urls')),
46 | ]
47 |
48 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
--------------------------------------------------------------------------------
/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.0/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 |
--------------------------------------------------------------------------------
/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 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ecommerce.settings')
9 | try:
10 | from django.core.management import execute_from_command_line
11 | except ImportError as exc:
12 | raise ImportError(
13 | "Couldn't import Django. Are you sure it's installed and "
14 | "available on your PYTHONPATH environment variable? Did you "
15 | "forget to activate a virtual environment?"
16 | ) from exc
17 | execute_from_command_line(sys.argv)
18 |
19 |
20 | if __name__ == '__main__':
21 | main()
22 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | asgiref==3.3.1
2 | braintree==4.5.0
3 | certifi==2020.11.8
4 | chardet==3.0.4
5 | coreapi==2.3.3
6 | coreschema==0.0.4
7 | dj-database-url==0.5.0
8 | Django==3.0.8
9 | django-cors-headers==3.5.0
10 | django-heroku==0.3.1
11 | djangorestframework==3.12.2
12 | drf-yasg==1.20.0
13 | gunicorn==20.0.4
14 | idna==2.10
15 | inflection==0.5.1
16 | itypes==1.2.0
17 | Jinja2==2.11.2
18 | MarkupSafe==1.1.1
19 | packaging==20.4
20 | Pillow==8.0.1
21 | psycopg2==2.8.6
22 | pyparsing==2.4.7
23 | pytz==2020.4
24 | requests==2.25.0
25 | ruamel.yaml==0.16.12
26 | ruamel.yaml.clib==0.2.2
27 | six==1.15.0
28 | sqlparse==0.4.1
29 | uritemplate==3.0.1
30 | urllib3==1.26.2
31 | whitenoise==5.2.0
32 |
--------------------------------------------------------------------------------