├── .gitignore
├── AMAZON API.postman_collection.json
├── Dockerfile
├── LICENSE
├── README.md
├── amazon_backend_api
├── __init__.py
├── admin.py
├── api
│ ├── helpers.py
│ ├── serializers.py
│ ├── urls.py
│ ├── utils.py
│ └── views.py
├── apps.py
├── manager.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_remove_amazonuser_first_name_and_more.py
│ ├── 0003_useraddress.py
│ ├── 0004_brand.py
│ ├── 0005_category.py
│ ├── 0006_subcategory.py
│ ├── 0007_size.py
│ ├── 0008_product.py
│ ├── 0009_productdetail.py
│ ├── 0010_color.py
│ ├── 0011_productdetail_color.py
│ ├── 0012_productdetail_is_stock_productdetail_stocks.py
│ ├── 0013_cart.py
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
├── amz-media
├── brands
│ └── logo
│ │ ├── download.png
│ │ └── hrx.png
└── products
│ ├── 519I05HaHjL._SX569._SX._UX._SY._UY_.jpg
│ ├── 51raYlT-AUL._UX569_.jpg
│ ├── 61UagAR6IcL._UX569_.jpg
│ ├── 61UagAR6IcL._UX569__xI8CtqU.jpg
│ ├── 61mUSVo0b7S._SX569._SX._UX._SY._UY_.jpg
│ └── 71mBMP1WTsL._SX569._SX._UX._SY._UY_.jpg
├── backend
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
├── docker-compose.yml
├── manage.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | __pycache__
3 | .DS_Store
4 | .idea
5 | db.sqlite3
--------------------------------------------------------------------------------
/AMAZON API.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "e52519e2-f852-456a-a417-3b6d77ad0d15",
4 | "name": "AMAZON API",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6 | },
7 | "item": [
8 | {
9 | "name": "Amz Auth",
10 | "item": [
11 | {
12 | "name": "Register User",
13 | "request": {
14 | "method": "POST",
15 | "header": [],
16 | "body": {
17 | "mode": "raw",
18 | "raw": "{\n \"full_name\" : \"xyz\",\n \"email\" : \"xyz@gmail.com\",\n \"password\" : \"xyz123\"\n}",
19 | "options": {
20 | "raw": {
21 | "language": "json"
22 | }
23 | }
24 | },
25 | "url": {
26 | "raw": "{{BASEURL}}user/register/",
27 | "host": [
28 | "{{BASEURL}}user"
29 | ],
30 | "path": [
31 | "register",
32 | ""
33 | ]
34 | }
35 | },
36 | "response": []
37 | },
38 | {
39 | "name": "Login User",
40 | "request": {
41 | "auth": {
42 | "type": "noauth"
43 | },
44 | "method": "POST",
45 | "header": [],
46 | "body": {
47 | "mode": "raw",
48 | "raw": "{\n \"email\" : \"xyz@gmail.com\",\n \"password\" : \"xyz123\"\n}",
49 | "options": {
50 | "raw": {
51 | "language": "json"
52 | }
53 | }
54 | },
55 | "url": {
56 | "raw": "{{BASEURL}}user/sign-in/",
57 | "host": [
58 | "{{BASEURL}}user"
59 | ],
60 | "path": [
61 | "sign-in",
62 | ""
63 | ]
64 | }
65 | },
66 | "response": []
67 | },
68 | {
69 | "name": "Get Access token",
70 | "request": {
71 | "auth": {
72 | "type": "noauth"
73 | },
74 | "method": "POST",
75 | "header": [],
76 | "body": {
77 | "mode": "raw",
78 | "raw": "{\n \"grant_type\" : \"refresh_token\",\n \"refresh_token\" : \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcwNzA1MTU3MiwiaWF0IjoxNjc1NTE1NTcyLCJqdGkiOiI1ZmNlNGQ0MDU4ODg0Mzc2OWRkYjY2ZTIzZTJhODRlZCIsImVtYWlsIjoiYWFzaGlzaGt1bWFyMTIzNzZAZ21haWwuY29tIn0.Hk-uG9XMIpGaEJfx7YipwxW9yj2yRxsLEorZiNkYoYE\"\n}",
79 | "options": {
80 | "raw": {
81 | "language": "json"
82 | }
83 | }
84 | },
85 | "url": {
86 | "raw": "{{BASEURL}}get/access-token/",
87 | "host": [
88 | "{{BASEURL}}get"
89 | ],
90 | "path": [
91 | "access-token",
92 | ""
93 | ]
94 | }
95 | },
96 | "response": []
97 | }
98 | ]
99 | },
100 | {
101 | "name": "Amz Address",
102 | "item": [
103 | {
104 | "name": "Get user address",
105 | "request": {
106 | "method": "GET",
107 | "header": [],
108 | "url": {
109 | "raw": "{{BASE_URL}}user/address/",
110 | "host": [
111 | "{{BASE_URL}}user"
112 | ],
113 | "path": [
114 | "address",
115 | ""
116 | ]
117 | }
118 | },
119 | "response": []
120 | },
121 | {
122 | "name": "Create user address",
123 | "request": {
124 | "auth": {
125 | "type": "bearer",
126 | "bearer": [
127 | {
128 | "key": "token",
129 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc0OTg1NTY4LCJpYXQiOjE2NzQ5ODE5NjgsImp0aSI6ImY3ODZhZThkY2U4YjRmOWJiYTE3YTRhYzY0Mjg5NmY4IiwiZW1haWwiOiJhc2hAZ21haWwuY29tIn0.3xRAKZf-09w0mNgypmh7Wo7QXWg8xSnGc0QAa9g6s-8",
130 | "type": "string"
131 | }
132 | ]
133 | },
134 | "method": "POST",
135 | "header": [],
136 | "body": {
137 | "mode": "raw",
138 | "raw": "{\n \"country\": \"India\",\n \"full_name\": \"md, julain\",\n \"mobile_number\": 992737373,\n \"pincode\": 110053,\n \"flat\": \"75\",\n \"street\": \"Block B, 6th avenue, rabibganj\",\n \"landmark\": \"rabibganj hospital\",\n \"town\": \"chittongong\",\n \"state\": \"DL\",\n \"default\": false,\n \"address_type\": \"Home\"\n}",
139 | "options": {
140 | "raw": {
141 | "language": "json"
142 | }
143 | }
144 | },
145 | "url": {
146 | "raw": "{{BASEURL}}user/address/",
147 | "host": [
148 | "{{BASEURL}}user"
149 | ],
150 | "path": [
151 | "address",
152 | ""
153 | ]
154 | }
155 | },
156 | "response": []
157 | },
158 | {
159 | "name": "Delete user address",
160 | "request": {
161 | "auth": {
162 | "type": "bearer",
163 | "bearer": [
164 | {
165 | "key": "token",
166 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MDc0MTcwLCJpYXQiOjE2NzUwNzA1NzAsImp0aSI6IjU4YTRkMzU4YzBlMDRiZWM4OGM4N2FlZjhiNTM3MmEzIiwiZW1haWwiOiJhc2hAZ21haWwuY29tIn0.o9BvjQhBBxr1wRlRbDQt5Ktxv9bfXFVdsmb2oQpupGc",
167 | "type": "string"
168 | }
169 | ]
170 | },
171 | "method": "DELETE",
172 | "header": [],
173 | "body": {
174 | "mode": "raw",
175 | "raw": "{\n \"id\" : 37\n}",
176 | "options": {
177 | "raw": {
178 | "language": "json"
179 | }
180 | }
181 | },
182 | "url": {
183 | "raw": "{{BASEURL}}user/address/",
184 | "host": [
185 | "{{BASEURL}}user"
186 | ],
187 | "path": [
188 | "address",
189 | ""
190 | ]
191 | }
192 | },
193 | "response": []
194 | },
195 | {
196 | "name": "Update user address",
197 | "request": {
198 | "auth": {
199 | "type": "bearer",
200 | "bearer": [
201 | {
202 | "key": "token",
203 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MDc0MTcwLCJpYXQiOjE2NzUwNzA1NzAsImp0aSI6IjU4YTRkMzU4YzBlMDRiZWM4OGM4N2FlZjhiNTM3MmEzIiwiZW1haWwiOiJhc2hAZ21haWwuY29tIn0.o9BvjQhBBxr1wRlRbDQt5Ktxv9bfXFVdsmb2oQpupGc",
204 | "type": "string"
205 | }
206 | ]
207 | },
208 | "method": "PUT",
209 | "header": [],
210 | "body": {
211 | "mode": "raw",
212 | "raw": "{\n \"id\" : 38,\n \"country\": \"India\",\n \"full_name\": \"Aashish Kumar\",\n \"mobile_number\": 434337332,\n \"pincode\": 110033,\n \"flat\": \"86\",\n \"street\": \"Block k house no 86 jahangir puri\",\n \"landmark\": \"metro station\",\n \"town\": \"Delhi\",\n \"state\": \"DL\",\n \"default\": false,\n \"address_type\": \"Home\"\n}",
213 | "options": {
214 | "raw": {
215 | "language": "json"
216 | }
217 | }
218 | },
219 | "url": {
220 | "raw": "{{BASEURL}}user/address/",
221 | "host": [
222 | "{{BASEURL}}user"
223 | ],
224 | "path": [
225 | "address",
226 | ""
227 | ]
228 | }
229 | },
230 | "response": []
231 | },
232 | {
233 | "name": "Set address default",
234 | "request": {
235 | "auth": {
236 | "type": "bearer",
237 | "bearer": [
238 | {
239 | "key": "token",
240 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MDU5OTU4LCJpYXQiOjE2NzUwNTYzNTgsImp0aSI6ImUzZWQyYTkzNDNmOTQ0ZWM4MjExNjYxNjNjZDk1ZTZkIiwiZW1haWwiOiJhc2hAZ21haWwuY29tIn0.9P4EC7YLlBDI-4Tq-Iq6-4mdu0d9OTUGof994pJ70XY",
241 | "type": "string"
242 | }
243 | ]
244 | },
245 | "method": "POST",
246 | "header": [],
247 | "url": {
248 | "raw": "{{BASEURL}}user/address/set/default/38/",
249 | "host": [
250 | "{{BASEURL}}user"
251 | ],
252 | "path": [
253 | "address",
254 | "set",
255 | "default",
256 | "38",
257 | ""
258 | ]
259 | }
260 | },
261 | "response": []
262 | }
263 | ]
264 | },
265 | {
266 | "name": "Products",
267 | "item": [
268 | {
269 | "name": "Get Brands",
270 | "request": {
271 | "method": "GET",
272 | "header": [],
273 | "url": {
274 | "raw": "{{BASEURL}}brands/",
275 | "host": [
276 | "{{BASEURL}}brands"
277 | ],
278 | "path": [
279 | ""
280 | ]
281 | }
282 | },
283 | "response": []
284 | },
285 | {
286 | "name": "Create new brand",
287 | "request": {
288 | "method": "POST",
289 | "header": [],
290 | "url": {
291 | "raw": "{{BASEURL}}brands/",
292 | "host": [
293 | "{{BASEURL}}brands"
294 | ],
295 | "path": [
296 | ""
297 | ]
298 | }
299 | },
300 | "response": []
301 | },
302 | {
303 | "name": "Get Subcategory1 products",
304 | "request": {
305 | "auth": {
306 | "type": "noauth"
307 | },
308 | "method": "GET",
309 | "header": [],
310 | "url": {
311 | "raw": "{{BASEURL}}products/fashion/men/",
312 | "host": [
313 | "{{BASEURL}}products"
314 | ],
315 | "path": [
316 | "fashion",
317 | "men",
318 | ""
319 | ]
320 | }
321 | },
322 | "response": []
323 | },
324 | {
325 | "name": "Get Subcategory2 products",
326 | "request": {
327 | "auth": {
328 | "type": "noauth"
329 | },
330 | "method": "GET",
331 | "header": [],
332 | "url": {
333 | "raw": "{{BASEURL}}products/fashion/Men/hoddies/",
334 | "host": [
335 | "{{BASEURL}}products"
336 | ],
337 | "path": [
338 | "fashion",
339 | "Men",
340 | "hoddies",
341 | ""
342 | ]
343 | }
344 | },
345 | "response": []
346 | },
347 | {
348 | "name": "Get single product details",
349 | "request": {
350 | "method": "GET",
351 | "header": [],
352 | "url": {
353 | "raw": "{{BASEURL}}product/product-id/1/product-detail/2/",
354 | "host": [
355 | "{{BASEURL}}product"
356 | ],
357 | "path": [
358 | "product-id",
359 | "1",
360 | "product-detail",
361 | "2",
362 | ""
363 | ]
364 | }
365 | },
366 | "response": []
367 | }
368 | ]
369 | },
370 | {
371 | "name": "Cart",
372 | "item": [
373 | {
374 | "name": "Get cart products",
375 | "request": {
376 | "auth": {
377 | "type": "bearer",
378 | "bearer": [
379 | {
380 | "key": "token",
381 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MzM4ODEyLCJpYXQiOjE2NzUzMzUyMTIsImp0aSI6IjRhZmQ0YzY2MjJkMjRhYzZiY2UyYzQ4NWRhZGJmNmJjIiwiZW1haWwiOiJhYXNoaXNoa3VtYXIxMjM3NkBnbWFpbC5jb20ifQ.ctKnbA1VsMetAyTlAj8VE42N_cNkXTYaegnSK-3jOiI",
382 | "type": "string"
383 | }
384 | ]
385 | },
386 | "method": "GET",
387 | "header": [],
388 | "url": {
389 | "raw": "{{BASEURL}}cart/",
390 | "host": [
391 | "{{BASEURL}}cart"
392 | ],
393 | "path": [
394 | ""
395 | ]
396 | }
397 | },
398 | "response": []
399 | },
400 | {
401 | "name": "Add product to cart",
402 | "request": {
403 | "auth": {
404 | "type": "bearer",
405 | "bearer": [
406 | {
407 | "key": "token",
408 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MzQzMjI4LCJpYXQiOjE2NzUzMzk2MjgsImp0aSI6ImJiZmI3Yzg1MTgyMzQyNjA4Yjc5NWY3YzJkZTZlYjQ0IiwiZW1haWwiOiJhYXNoaXNoa3VtYXIxMjM3NkBnbWFpbC5jb20ifQ.BczOp0fv6dsLFO6IvCnJuSDe7Motw04NdBxphTT1J8k",
409 | "type": "string"
410 | }
411 | ]
412 | },
413 | "method": "POST",
414 | "header": [],
415 | "body": {
416 | "mode": "raw",
417 | "raw": "{\n \"product_id\" : 1\n}",
418 | "options": {
419 | "raw": {
420 | "language": "json"
421 | }
422 | }
423 | },
424 | "url": {
425 | "raw": "{{BASEURL}}cart/",
426 | "host": [
427 | "{{BASEURL}}cart"
428 | ],
429 | "path": [
430 | ""
431 | ]
432 | }
433 | },
434 | "response": []
435 | },
436 | {
437 | "name": "Delete product from cart",
438 | "request": {
439 | "auth": {
440 | "type": "bearer",
441 | "bearer": [
442 | {
443 | "key": "token",
444 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MzQzMjI4LCJpYXQiOjE2NzUzMzk2MjgsImp0aSI6ImJiZmI3Yzg1MTgyMzQyNjA4Yjc5NWY3YzJkZTZlYjQ0IiwiZW1haWwiOiJhYXNoaXNoa3VtYXIxMjM3NkBnbWFpbC5jb20ifQ.BczOp0fv6dsLFO6IvCnJuSDe7Motw04NdBxphTT1J8k",
445 | "type": "string"
446 | }
447 | ]
448 | },
449 | "method": "DELETE",
450 | "header": [],
451 | "body": {
452 | "mode": "raw",
453 | "raw": "{\n \"product_id\" : 1\n}",
454 | "options": {
455 | "raw": {
456 | "language": "json"
457 | }
458 | }
459 | },
460 | "url": {
461 | "raw": "{{BASEURL}}cart/",
462 | "host": [
463 | "{{BASEURL}}cart"
464 | ],
465 | "path": [
466 | ""
467 | ]
468 | }
469 | },
470 | "response": []
471 | },
472 | {
473 | "name": "Update the product quantity",
474 | "request": {
475 | "auth": {
476 | "type": "bearer",
477 | "bearer": [
478 | {
479 | "key": "token",
480 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc1MzQ2OTMyLCJpYXQiOjE2NzUzNDMzMzIsImp0aSI6IjE4YWM5ZjZmZWMyNTQ0ZmE5MWE2YjI3ZWZhMDkwNGNhIiwiZW1haWwiOiJhYXNoaXNoa3VtYXIxMjM3NkBnbWFpbC5jb20ifQ.8saOs82UttJHL0aXWM6_cTnfqZJFh2BVH3ooU8zCCuM",
481 | "type": "string"
482 | }
483 | ]
484 | },
485 | "method": "PATCH",
486 | "header": [],
487 | "body": {
488 | "mode": "raw",
489 | "raw": "{\n \"id\" : 6,\n \"quantity\" : 50\n}",
490 | "options": {
491 | "raw": {
492 | "language": "json"
493 | }
494 | }
495 | },
496 | "url": {
497 | "raw": "{{BASEURL}}cart/",
498 | "host": [
499 | "{{BASEURL}}cart"
500 | ],
501 | "path": [
502 | ""
503 | ]
504 | }
505 | },
506 | "response": []
507 | }
508 | ]
509 | }
510 | ],
511 | "variable": [
512 | {
513 | "key": "http://localhost:8000/api/amz/",
514 | "value": "BASE_URL"
515 | },
516 | {
517 | "key": "BASE_URL",
518 | "value": "http://localhost:8000/api/amz/"
519 | },
520 | {
521 | "key": "BASEURL",
522 | "value": "http://localhost:8001/api/amz/"
523 | }
524 | ]
525 | }
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.10
2 |
3 | ENV PYTHONUNBUFFERED=1
4 |
5 | WORKDIR /code
6 |
7 | COPY requirements.txt .
8 |
9 | RUN pip install -r requirements.txt
10 |
11 | COPY . .
12 |
13 | CMD ["python","manage.py","runserver","0.0.0.0:8000"]
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Aashishkumar123
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Amazon Clone API
2 | Amazon clone api using django and django rest framework.
3 |
4 | ## Requirements
5 |
6 | Python 3.6+
7 |
8 | ## Installation
9 |
10 | ```console
11 | $ pip install -r requirements.txt
12 | ```
13 | ## Database setting
14 | Go to settings.py file and change the database settings.
15 | ```
16 | DATABASES = {
17 | 'default': {
18 | 'ENGINE': 'django.db.backends.postgresql',
19 | 'NAME': 'your-database-name',
20 | 'USER': 'Your-username',
21 | 'PASSWORD': 'Your-password',
22 | 'HOST': 'localhost',
23 | 'PORT': '5432',
24 | }
25 | }
26 | ```
27 | and then hit the migrate command to successfully create database table..
28 |
29 | ```console
30 | $ python manage.py migrate
31 | ```
32 | ## Run the project
33 | To run the project is very simple just hit this command
34 | ```console
35 | $ python manage.py runserver
36 | ```
37 |
38 | ## API Documentations
39 | If you want api documentations simple visit this
40 |
41 | swagger docs
42 | ```console
43 | $ http://localhost:8000/api/amz/swagger/
44 | ```
45 | ReDocs docs
46 | ```console
47 | $ http://localhost:8000/api/amz/redoc/
48 | ```
49 | ## Testing
50 | If you want to run the test cases you can simply run this command
51 | ```console
52 | $ python manage.py test
53 | ```
54 | Hence all api testing code are wriiten in test.py file.
55 |
56 | ## Code Format
57 | If you want to format the code you can simply run those commands.
58 |
59 | using black package
60 | ```console
61 | $ black amazon_backend_api/api/views.py
62 | ```
63 | using flake8 package
64 | ```console
65 | $ flake8 amazon_backend_api/api/views.py
66 | ```
67 |
68 | ## Postman api collection
69 | You can also export the postman api collection and import in postman.
70 |
71 | ## Run server through Docker
72 | If you want to run the server using docker-compose hit the following command.
73 |
74 | ```docker
75 | $ docker-compose up --build
76 | ```
77 |
--------------------------------------------------------------------------------
/amazon_backend_api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amazon_backend_api/__init__.py
--------------------------------------------------------------------------------
/amazon_backend_api/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from amazon_backend_api.models import (
3 | Amazonuser,
4 | UserAddress,
5 | Brand,
6 | Category,
7 | Subcategory,
8 | Size,
9 | Product,
10 | ProductDetail,
11 | Color,
12 | Cart,
13 | )
14 |
15 | admin.site.register(Amazonuser)
16 | admin.site.register(UserAddress)
17 | admin.site.register(Brand)
18 | admin.site.register(Category)
19 | admin.site.register(Subcategory)
20 | admin.site.register(Size)
21 | admin.site.register(Product)
22 | admin.site.register(ProductDetail)
23 | admin.site.register(Color)
24 | admin.site.register(Cart)
25 |
--------------------------------------------------------------------------------
/amazon_backend_api/api/helpers.py:
--------------------------------------------------------------------------------
1 | from rest_framework_simplejwt.tokens import RefreshToken
2 | from rest_framework_simplejwt.authentication import JWTAuthentication
3 | from amazon_backend_api.models import Amazonuser
4 |
5 |
6 | JWT_authenticator = JWTAuthentication()
7 |
8 |
9 | def get_tokens_for_user(user):
10 |
11 | refresh = RefreshToken.for_user(user)
12 |
13 | return {
14 | "email": user.email,
15 | "full name": user.full_name,
16 | "refresh": str(refresh),
17 | "access": str(refresh.access_token),
18 | }
19 |
20 |
21 | def get_user_from_token(request):
22 |
23 | response = JWT_authenticator.authenticate(request)
24 |
25 | if response is not None:
26 | user, token = response
27 | return user
28 |
29 |
30 | def get_access_token_from_refresh_token(request):
31 |
32 | if request.data["grant_type"] == "refresh_token":
33 | access_token = RefreshToken(request.data["refresh_token"]).access_token
34 | request.META["HTTP_AUTHORIZATION"] = "Bearer " + str(access_token)
35 | user = get_user_from_token(request)
36 | data = get_tokens_for_user(Amazonuser.objects.get(email=user))
37 | return data
38 | return []
39 |
--------------------------------------------------------------------------------
/amazon_backend_api/api/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from amazon_backend_api.models import (
3 | Amazonuser,
4 | UserAddress,
5 | Brand,
6 | Product,
7 | ProductDetail,
8 | Size,
9 | Cart,
10 | )
11 | from rest_framework.serializers import ALL_FIELDS
12 | from django.contrib.auth.hashers import make_password
13 |
14 |
15 | class AmazonuserSerializer(serializers.ModelSerializer):
16 | class Meta:
17 | model = Amazonuser
18 | fields = ["email", "full_name", "password"]
19 |
20 | def create(self, validated_data):
21 | validated_data["password"] = make_password(
22 | validated_data.get("password")
23 | )
24 | return super(AmazonuserSerializer, self).create(validated_data)
25 |
26 |
27 | class AmazonuserLoginSerializer(serializers.ModelSerializer):
28 |
29 | email = serializers.EmailField()
30 |
31 | class Meta:
32 | model = Amazonuser
33 | fields = ["email", "password"]
34 |
35 |
36 | class AmazonuserAddressSerializer(serializers.ModelSerializer):
37 |
38 | user = serializers.CharField(source="user.email", read_only=True)
39 |
40 | class Meta:
41 | model = UserAddress
42 | fields = ALL_FIELDS
43 |
44 |
45 | class BrandSerializer(serializers.ModelSerializer):
46 | class Meta:
47 | model = Brand
48 | fields = ALL_FIELDS
49 |
50 |
51 | class ProductSerializer(serializers.ModelSerializer):
52 |
53 | brand = serializers.CharField(source="brand.name", read_only=True)
54 | category = serializers.CharField(source="category.name", read_only=True)
55 | subcategory1 = serializers.CharField(source="subcategory1.name", read_only=True)
56 | subcategory2 = serializers.CharField(source="subcategory2.name", read_only=True)
57 |
58 | class Meta:
59 | model = Product
60 | fields = [
61 | "id",
62 | "name",
63 | "brand",
64 | "category",
65 | "subcategory1",
66 | "subcategory2"
67 | ]
68 |
69 |
70 | class SizeSerializer(serializers.ModelSerializer):
71 | class Meta:
72 | model = Size
73 | fields = ["name"]
74 |
75 |
76 | class ProductDetailsSerializer(serializers.ModelSerializer):
77 |
78 | product = ProductSerializer(read_only=True)
79 | size = SizeSerializer(read_only=True, many=True)
80 | color = serializers.CharField(source="color.code", read_only=True)
81 |
82 | class Meta:
83 | model = ProductDetail
84 | fields = [
85 | "id",
86 | "product",
87 | "size",
88 | "color",
89 | "description",
90 | "mrp",
91 | "discount",
92 | "stocks",
93 | "image1",
94 | "image2",
95 | "image3",
96 | ]
97 |
98 |
99 | class CartSerializer(serializers.ModelSerializer):
100 |
101 | user = serializers.CharField(source="user.email", read_only=True)
102 | product = ProductDetailsSerializer(read_only=True)
103 |
104 | class Meta:
105 | model = Cart
106 | fields = ["id", "user", "product", "quantity"]
107 |
108 |
109 | class RegenerateAccessTokenSerializer(serializers.Serializer):
110 |
111 | grant_type = serializers.CharField(
112 | error_messages={"required": "grant type may not be blank"}
113 | )
114 | refresh_token = serializers.CharField(
115 | error_messages={"required": "refresh token may not be blank"}
116 | )
117 |
--------------------------------------------------------------------------------
/amazon_backend_api/api/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path, re_path
2 | from amazon_backend_api.api import views
3 |
4 | from rest_framework import permissions
5 | from drf_yasg.views import get_schema_view
6 | from drf_yasg import openapi
7 |
8 |
9 | schema_view = get_schema_view(
10 | openapi.Info(
11 | title="Snippets API",
12 | default_version="v1",
13 | description="Test description",
14 | terms_of_service="https://www.google.com/policies/terms/",
15 | contact=openapi.Contact(email="contact@snippets.local"),
16 | license=openapi.License(name="BSD License"),
17 | ),
18 | public=True,
19 | permission_classes=[permissions.AllowAny],
20 | )
21 |
22 |
23 | urlpatterns = [
24 | path("user/register/", views.RegisterAPIView.as_view(), name="amz-user-register"),
25 | path("user/sign-in/", views.SigninAPIView.as_view(), name="amz-user-sign-in"),
26 | path(
27 | "get/access-token/",
28 | views.RegenerateAccessToken.as_view(),
29 | name="amz-get-access-token",
30 | ),
31 | path("user/address/", views.UserAddressAPIView.as_view(), name="amz-user-address"),
32 | path(
33 | "user/address/set/default//",
34 | views.SetdefaultAddressAPIView.as_view(),
35 | name="amz-user-address-set-default",
36 | ),
37 | path("brands/", views.BrandAPIView.as_view(), name="amz-brands"),
38 | path(
39 | "products/fashion//",
40 | views.ProductsAPIView.as_view(),
41 | name="amz-products-subcategory1",
42 | ),
43 | path(
44 | "products/fashion///",
45 | views.ProductsAPIView.as_view(),
46 | name="amz-products-subcategory2",
47 | ),
48 | path(
49 | "product/product-id//product-detail//",
50 | views.ProductDetailsAPIView.as_view(),
51 | name="amz-product-details",
52 | ),
53 | path("cart/", views.CartAPIView.as_view(), name="amz-cart"),
54 | re_path(
55 | r"^swagger(?P\.json|\.yaml)$",
56 | schema_view.without_ui(cache_timeout=0),
57 | name="schema-json",
58 | ),
59 | re_path(
60 | r"^swagger/$",
61 | schema_view.with_ui("swagger", cache_timeout=0),
62 | name="schema-swagger-ui",
63 | ),
64 | re_path(
65 | r"^redoc/$", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"
66 | ),
67 | ]
68 |
--------------------------------------------------------------------------------
/amazon_backend_api/api/utils.py:
--------------------------------------------------------------------------------
1 | INDIAN_STATES = {
2 | "AN":"Andaman and Nicobar Islands",
3 | "AP":"Andhra Pradesh",
4 | "AR":"Arunachal Pradesh",
5 | "AS":"Assam",
6 | "BR":"Bihar",
7 | "CG":"Chandigarh",
8 | "CH":"Chhattisgarh",
9 | "DN":"Dadra and Nagar Haveli",
10 | "DD":"Daman and Diu",
11 | "DL":"Delhi",
12 | "GA":"Goa",
13 | "GJ":"Gujarat",
14 | "HR":"Haryana",
15 | "HP":"Himachal Pradesh",
16 | "JK":"Jammu and Kashmir",
17 | "JH":"Jharkhand",
18 | "KA":"Karnataka",
19 | "KL":"Kerala",
20 | "LA":"Ladakh",
21 | "LD":"Lakshadweep",
22 | "MP":"Madhya Pradesh",
23 | "MH":"Maharashtra",
24 | "MN":"Manipur",
25 | "ML":"Meghalaya",
26 | "MZ":"Mizoram",
27 | "NL":"Nagaland",
28 | "OR":"Odisha",
29 | "PY":"Puducherry",
30 | "PB":"Punjab",
31 | "RJ":"Rajasthan",
32 | "SK":"Sikkim",
33 | "TN":"Tamil Nadu",
34 | "TS":"Telangana",
35 | "TR":"Tripura",
36 | "UP":"Uttar Pradesh",
37 | "UK":"Uttarakhand",
38 | "WB":"West Bengal"
39 | }
40 |
--------------------------------------------------------------------------------
/amazon_backend_api/api/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import authenticate
2 | from rest_framework import status
3 | from rest_framework.permissions import IsAuthenticated
4 | from rest_framework.response import Response
5 | from rest_framework.views import APIView
6 |
7 | from amazon_backend_api.api.helpers import (
8 | get_access_token_from_refresh_token,
9 | get_tokens_for_user,
10 | get_user_from_token,
11 | )
12 | from amazon_backend_api.api.serializers import (
13 | AmazonuserAddressSerializer,
14 | AmazonuserLoginSerializer,
15 | AmazonuserSerializer,
16 | BrandSerializer,
17 | CartSerializer,
18 | ProductDetailsSerializer,
19 | RegenerateAccessTokenSerializer,
20 | )
21 | from amazon_backend_api.models import (
22 | Amazonuser,
23 | Brand,
24 | Cart,
25 | Product,
26 | ProductDetail,
27 | Subcategory,
28 | UserAddress,
29 | )
30 |
31 |
32 | class RegisterAPIView(APIView):
33 | """This api used for register new user"""
34 |
35 | def post(self, request):
36 | """Handle post request"""
37 |
38 | serializer = AmazonuserSerializer(data=request.data)
39 |
40 | """it will check data validation"""
41 | if serializer.is_valid():
42 |
43 | """create a new user"""
44 | amz_user = serializer.save()
45 |
46 | """return the user information and tokens"""
47 | res_data = get_tokens_for_user(Amazonuser.objects.get(email=amz_user.email))
48 |
49 | """response result"""
50 | response = {
51 | "status": status.HTTP_201_CREATED,
52 | "message": "created",
53 | "data": res_data,
54 | }
55 | return Response(response, status=status.HTTP_201_CREATED)
56 |
57 | """if validation failed it return this"""
58 | response = {
59 | "status": status.HTTP_400_BAD_REQUEST,
60 | "message": "bad request",
61 | "data": serializer.errors,
62 | }
63 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
64 |
65 |
66 | class SigninAPIView(APIView):
67 | """""This api is handling login""" ""
68 |
69 | def post(self, request):
70 | """Handle post request"""
71 |
72 | login_serializer = AmazonuserLoginSerializer(data=request.data)
73 |
74 | """it will check data validation"""
75 | if login_serializer.is_valid():
76 |
77 | """get email and password"""
78 | email = login_serializer.validated_data["email"]
79 | password = login_serializer.validated_data["password"]
80 |
81 | """it will check the credentials is valid or not"""
82 | user = authenticate(request, email=email, password=password)
83 |
84 | """it will return access token if credentials are ok"""
85 | if user is not None:
86 |
87 | """return the user information and tokens"""
88 | res_data = get_tokens_for_user(Amazonuser.objects.get(email=email))
89 | response = {
90 | "status": status.HTTP_200_OK,
91 | "message": "success",
92 | "data": res_data,
93 | }
94 | return Response(response, status=status.HTTP_200_OK)
95 | else:
96 | """otherwise return this response"""
97 | response = {
98 | "status": status.HTTP_401_UNAUTHORIZED,
99 | "message": "Invalid Email or Password",
100 | }
101 | return Response(response, status=status.HTTP_401_UNAUTHORIZED)
102 |
103 | """if validation failed it return this"""
104 | response = {
105 | "status": status.HTTP_400_BAD_REQUEST,
106 | "message": "bad request",
107 | "data": login_serializer.errors,
108 | }
109 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
110 |
111 |
112 | class RegenerateAccessToken(APIView):
113 | """This api is used to regenerate access token"""
114 |
115 | def post(self, request):
116 | """Handle post request"""
117 |
118 | reg_access_token_serializer = RegenerateAccessTokenSerializer(data=request.data)
119 |
120 | """it will check data validation"""
121 | if reg_access_token_serializer.is_valid():
122 |
123 | """return access token"""
124 | data = get_access_token_from_refresh_token(request)
125 | response = {
126 | "status": status.HTTP_200_OK,
127 | "message": "success",
128 | "data": data,
129 | }
130 | return Response(response, status=status.HTTP_200_OK)
131 |
132 | """if validation failed it return this"""
133 | response = {
134 | "status": status.HTTP_400_BAD_REQUEST,
135 | "message": "bad request",
136 | "data": reg_access_token_serializer.errors,
137 | }
138 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
139 |
140 |
141 | class UserAddressAPIView(APIView):
142 | """This api is used to get , update , delete , create the user address"""
143 |
144 | permission_classes = [IsAuthenticated]
145 |
146 | def get(self, request):
147 | print(request.user)
148 | user = get_user_from_token(request)
149 | address = UserAddress.objects.filter(user=user)
150 | serialize_address = AmazonuserAddressSerializer(address, many=True)
151 | response = {
152 | "status": status.HTTP_200_OK,
153 | "message": "OK",
154 | "data": serialize_address.data,
155 | }
156 | return Response(response, status=status.HTTP_200_OK)
157 |
158 | def post(self, request):
159 | data = request.data
160 | user = get_user_from_token(request)
161 | serialize_address = AmazonuserAddressSerializer(data=data)
162 | if serialize_address.is_valid():
163 | created_adrs = serialize_address.save(user=user)
164 | response = {
165 | "status": status.HTTP_201_CREATED,
166 | "message": "address created",
167 | "data": AmazonuserAddressSerializer(
168 | UserAddress.objects.get(id=created_adrs.id)
169 | ).data,
170 | }
171 | return Response(response, status=status.HTTP_201_CREATED)
172 | response = {
173 | "status": status.HTTP_400_BAD_REQUEST,
174 | "message": "bad request",
175 | "data": serialize_address.errors,
176 | }
177 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
178 |
179 | def put(self, request):
180 | user = get_user_from_token(request)
181 | if "id" not in request.data:
182 | response = {
183 | "status": "400",
184 | "message": "bad request",
185 | "data": {"id": ["This field is required."]},
186 | }
187 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
188 | data = request.data
189 |
190 | try:
191 | user_address = UserAddress.objects.filter(user=user)
192 | adrs_id = user_address.get(id=data["id"])
193 | except UserAddress.DoesNotExist:
194 | response = {
195 | "status": status.HTTP_400_BAD_REQUEST,
196 | "message": "Id does not exist.",
197 | }
198 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
199 |
200 | serialize_address = AmazonuserAddressSerializer(adrs_id, data=data)
201 | if serialize_address.is_valid():
202 | updated_adrs = serialize_address.save()
203 | response = {
204 | "status": status.HTTP_200_OK,
205 | "message": "address updated",
206 | "data": AmazonuserAddressSerializer(
207 | UserAddress.objects.get(id=updated_adrs.id)
208 | ).data,
209 | }
210 | return Response(response, status=status.HTTP_200_OK)
211 | response = {
212 | "status": status.HTTP_400_BAD_REQUEST,
213 | "message": "bad request",
214 | "data": serialize_address.errors,
215 | }
216 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
217 |
218 | def delete(self, request):
219 | user = get_user_from_token(request)
220 | if "id" not in request.data or not request.data["id"]:
221 | response = {
222 | "status": status.HTTP_400_BAD_REQUEST,
223 | "message": "bad request",
224 | "data": {"id": ["This field is required."]},
225 | }
226 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
227 |
228 | address_id = request.data["id"]
229 |
230 | try:
231 | UserAddress.objects.filter(user=user).get(id=address_id).delete()
232 | except UserAddress.DoesNotExist:
233 | response = {
234 | "status": status.HTTP_400_BAD_REQUEST,
235 | "message": "Id does not exist.",
236 | }
237 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
238 |
239 | response = {"status": status.HTTP_204_NO_CONTENT, "message": "Address deleted."}
240 | return Response(response, status=status.HTTP_204_NO_CONTENT)
241 |
242 |
243 | """
244 | This api will set a default address....
245 | """
246 |
247 |
248 | class SetdefaultAddressAPIView(APIView):
249 |
250 | permission_classes = [IsAuthenticated]
251 |
252 | def post(self, request, id):
253 | user = get_user_from_token(request)
254 | df_adrs = UserAddress.objects.filter(user=user)
255 | df_adrs.filter(default=True).update(default=False)
256 |
257 | try:
258 | update_default_adrs = df_adrs.get(id=id)
259 | update_default_adrs.default = True
260 | update_default_adrs.save()
261 | except UserAddress.DoesNotExist:
262 | response = {"status": status.HTTP_404_NOT_FOUND, "message": "ID not found"}
263 | return Response(response, status=status.HTTP_404_NOT_FOUND)
264 |
265 | response = {"status": status.HTTP_200_OK, "message": "success"}
266 | return Response(response, status=status.HTTP_200_OK)
267 |
268 |
269 | """
270 | This api will GET and Save the new brands
271 | """
272 |
273 |
274 | class BrandAPIView(APIView):
275 |
276 | permission_classes = [IsAuthenticated]
277 |
278 | def get(self, request):
279 | brands = Brand.objects.all()
280 | brand_serializer = BrandSerializer(brands, many=True)
281 | response = {
282 | "status": status.HTTP_200_OK,
283 | "message": "success",
284 | "data": brand_serializer.data,
285 | }
286 | return Response(response, status=status.HTTP_200_OK)
287 |
288 | def post(self, request):
289 | data = request.data
290 | brand_serializer = BrandSerializer(data=data)
291 | if brand_serializer.is_valid():
292 | brand = brand_serializer.save()
293 | response = {
294 | "status": status.HTTP_201_CREATED,
295 | "message": "brand created",
296 | "data": BrandSerializer(Brand.objects.get(id=brand.id)).data,
297 | }
298 | return Response(response, status=status.HTTP_201_CREATED)
299 | response = {
300 | "status": status.HTTP_400_BAD_REQUEST,
301 | "message": "bad request",
302 | "data": brand_serializer.errors,
303 | }
304 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
305 |
306 |
307 | class ProductsAPIView(APIView):
308 | """
309 | This api return all the products on the base of its subcategory
310 | """
311 |
312 | def get(self, request, subcategory1, subcategory2=None):
313 | if subcategory2:
314 | products = Product.objects.filter(
315 | subcategory1=Subcategory.objects.filter(
316 | name__iexact=subcategory1
317 | ).first(),
318 | subcategory2=Subcategory.objects.filter(
319 | name__iexact=subcategory2
320 | ).first(),
321 | ).first()
322 | else:
323 | products = Product.objects.filter(
324 | subcategory1=Subcategory.objects.filter(
325 | name__iexact=subcategory1
326 | ).first()
327 | ).first()
328 |
329 | allproducts = ProductDetail.objects.filter(product=products)
330 | allproducts_serializer = ProductDetailsSerializer(allproducts, many=True)
331 |
332 | response = {
333 | "status": status.HTTP_200_OK,
334 | "message": "success",
335 | "data": allproducts_serializer.data,
336 | }
337 | return Response(response, status=status.HTTP_200_OK)
338 |
339 |
340 | class ProductDetailsAPIView(APIView):
341 | """
342 | This api return single product details
343 | """
344 |
345 | def get(self, request, product_id, product_detail_id):
346 | try:
347 | product = Product.objects.get(id=product_id)
348 | except Product.DoesNotExist:
349 | response = {
350 | "status": status.HTTP_400_BAD_REQUEST,
351 | "message": "product not found.",
352 | }
353 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
354 |
355 | product_details = ProductDetail.objects.filter(product=product)
356 |
357 | if not product_details.filter(id=product_detail_id):
358 | response = {
359 | "status": status.HTTP_400_BAD_REQUEST,
360 | "message": "product not found.",
361 | "data": [],
362 | }
363 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
364 |
365 | product_details_serializer = ProductDetailsSerializer(
366 | product_details, many=True
367 | )
368 |
369 | response = {
370 | "status": status.HTTP_200_OK,
371 | "message": "success",
372 | "active_product_detail_id": product_detail_id,
373 | "data": product_details_serializer.data,
374 | }
375 | return Response(response, status=status.HTTP_200_OK)
376 |
377 |
378 | class CartAPIView(APIView):
379 | """
380 | cart api that will get all the products of an user
381 | cart api that will add product to the cart of an user
382 | cart api that will update the product quantity of an user
383 | cart api that will remove the product from cart of an user
384 | """
385 |
386 | permission_classes = [IsAuthenticated]
387 |
388 | """
389 | Return all the products from cart for particular user
390 | """
391 |
392 | def get(self, request):
393 | user = get_user_from_token(request)
394 | cart = Cart.objects.filter(user=user)
395 | cart_serializer = CartSerializer(cart, many=True)
396 | response = {
397 | "status": status.HTTP_200_OK,
398 | "message": "success",
399 | "data": cart_serializer.data,
400 | }
401 | return Response(response, status=status.HTTP_200_OK)
402 |
403 | """
404 | Add the product to cart for a particular user
405 | """
406 |
407 | def post(self, request):
408 | user = get_user_from_token(request)
409 | data = request.data
410 |
411 | """
412 | This will response 404 if product_id not in request data
413 | """
414 | if "product_id" not in data:
415 | response = {
416 | "status": status.HTTP_400_BAD_REQUEST,
417 | "message": "bad request",
418 | "data": {"product_id": "Product id should not empty"},
419 | }
420 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
421 |
422 | """
423 | This will response 404 status code if get wrong product id
424 | """
425 | try:
426 | product_id = ProductDetail.objects.get(id=request.data["product_id"])
427 | except ProductDetail.DoesNotExist:
428 | response = {
429 | "status": status.HTTP_400_BAD_REQUEST,
430 | "message": "bad request",
431 | "data": {"product_id": "Invalid product id"},
432 | }
433 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
434 |
435 | """
436 | This will check product already in cart then will response 404 status code
437 | """
438 | if Cart.objects.filter(user=user, product=data["product_id"]).exists():
439 | response = {
440 | "status": status.HTTP_400_BAD_REQUEST,
441 | "message": "bad request",
442 | "data": {"product": "Product already in cart"},
443 | }
444 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
445 |
446 | """
447 | If everything fine this will add product to cart
448 | """
449 | cart_serializer = CartSerializer(data=data)
450 | if cart_serializer.is_valid():
451 | cart_serializer.save(user=user, product=product_id)
452 | response = {
453 | "status": status.HTTP_201_CREATED,
454 | "message": "proudct added to cart",
455 | }
456 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
457 |
458 | """
459 | else return 404 status code
460 | """
461 | response = {
462 | "status": status.HTTP_400_BAD_REQUEST,
463 | "message": "bad request",
464 | "data": cart_serializer.errors,
465 | }
466 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
467 |
468 | """
469 | This will update the product quantity of a particular user
470 | """
471 |
472 | def patch(self, request):
473 | data = request.data
474 | user = get_user_from_token(request)
475 |
476 | """
477 | This will check request data is having id or not
478 | """
479 | if "id" not in data:
480 | response = {
481 | "status": status.HTTP_400_BAD_REQUEST,
482 | "message": "bad request",
483 | "data": {"id": ["id is required"]},
484 | }
485 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
486 |
487 | """
488 | This will check the cart id is belong the authenticated user
489 | """
490 | if not Cart.objects.filter(user=user, id=data["id"]).exists():
491 | response = {
492 | "status": status.HTTP_400_BAD_REQUEST,
493 | "message": "bad request",
494 | "data": {"id": ["invalid cart id"]},
495 | }
496 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
497 |
498 | """
499 | This will check the validation and update the product quantity
500 | """
501 | cart_serializer = CartSerializer(
502 | instance=Cart.objects.get(id=data["id"]), data=data, partial=True
503 | )
504 | if cart_serializer.is_valid():
505 | cart_serializer.save()
506 | response = {
507 | "status": status.HTTP_202_ACCEPTED,
508 | "message": "quantity updated",
509 | "data": CartSerializer(
510 | Cart.objects.get(id=cart_serializer.data["id"])
511 | ).data,
512 | }
513 | return Response(response, status=status.HTTP_202_ACCEPTED)
514 |
515 | """
516 | otherwise it raise the validation
517 | """
518 | response = {
519 | "status": status.HTTP_400_BAD_REQUEST,
520 | "message": "bad request",
521 | "data": cart_serializer.errors,
522 | }
523 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
524 |
525 | """
526 | This will remove product from cart of a particular user
527 | """
528 |
529 | def delete(self, request):
530 | data = request.data
531 | user = get_user_from_token(request)
532 | """
533 | This will response 404 if product_id not in request data
534 | """
535 | if "product_id" not in data:
536 | response = {
537 | "status": status.HTTP_400_BAD_REQUEST,
538 | "message": "bad request",
539 | "data": {"product_id": "Product id should not empty"},
540 | }
541 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
542 |
543 | """
544 | This will check product avaliable in cart to delete
545 | """
546 | if Cart.objects.filter(user=user, product=data["product_id"]).exists():
547 | Cart.objects.get(product=data["product_id"]).delete()
548 | response = {
549 | "status": status.HTTP_204_NO_CONTENT,
550 | "message": "product remove from cart",
551 | }
552 | return Response(response, status=status.HTTP_204_NO_CONTENT)
553 |
554 | """
555 | other response inavlid product id
556 | """
557 | response = {
558 | "status": status.HTTP_400_BAD_REQUEST,
559 | "message": "bad request",
560 | "data": {"product_id": "Invalid product id"},
561 | }
562 | return Response(response, status=status.HTTP_400_BAD_REQUEST)
563 |
--------------------------------------------------------------------------------
/amazon_backend_api/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class AmazonBackendApiConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "amazon_backend_api"
7 |
--------------------------------------------------------------------------------
/amazon_backend_api/manager.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.base_user import BaseUserManager
2 | from django.utils.translation import gettext_lazy as _
3 |
4 |
5 | class AmazonuserManager(BaseUserManager):
6 | """
7 | Custom user model manager where email is the unique identifiers
8 | for authentication instead of usernames.
9 | """
10 |
11 | def create_user(self, email, password, **extra_fields):
12 | """
13 | Create and save a User with the given email and password.
14 | """
15 | if not email:
16 | raise ValueError(_("The Email must be set"))
17 | email = self.normalize_email(email)
18 | user = self.model(email=email, **extra_fields)
19 | user.set_password(password)
20 | user.save()
21 | return user
22 |
23 | def create_superuser(self, email, password, **extra_fields):
24 | """
25 | Create and save a SuperUser with the given email and password.
26 | """
27 | extra_fields.setdefault("is_staff", True)
28 | extra_fields.setdefault("is_superuser", True)
29 | extra_fields.setdefault("is_active", True)
30 |
31 | if extra_fields.get("is_staff") is not True:
32 | raise ValueError(_("Superuser must have is_staff=True."))
33 | if extra_fields.get("is_superuser") is not True:
34 | raise ValueError(_("Superuser must have is_superuser=True."))
35 | return self.create_user(email, password, **extra_fields)
36 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2 on 2023-01-27 11:32
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='Amazonuser',
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, verbose_name='email address')),
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 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0002_remove_amazonuser_first_name_and_more.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-01-28 04:54
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0001_initial"),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(model_name="amazonuser", name="first_name",),
14 | migrations.RemoveField(model_name="amazonuser", name="last_name",),
15 | migrations.AddField(
16 | model_name="amazonuser",
17 | name="full_name",
18 | field=models.CharField(
19 | default="", max_length=100, verbose_name="full name"
20 | ),
21 | preserve_default=False,
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0003_useraddress.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-01-28 09:20
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 | dependencies = [
11 | ("amazon_backend_api", "0002_remove_amazonuser_first_name_and_more"),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name="UserAddress",
17 | fields=[
18 | (
19 | "id",
20 | models.BigAutoField(
21 | auto_created=True,
22 | primary_key=True,
23 | serialize=False,
24 | verbose_name="ID",
25 | ),
26 | ),
27 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
28 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
29 | (
30 | "country",
31 | models.CharField(
32 | choices=[("India", "India")],
33 | max_length=100,
34 | verbose_name="Country",
35 | ),
36 | ),
37 | (
38 | "full_name",
39 | models.CharField(
40 | max_length=100, verbose_name="Full name (First and last name)"
41 | ),
42 | ),
43 | ("mobile_number", models.IntegerField(verbose_name="Mobile number")),
44 | ("pincode", models.IntegerField(verbose_name="Pincode")),
45 | (
46 | "flat",
47 | models.CharField(
48 | max_length=200,
49 | verbose_name="Flat, House no., Building, Company, Apartment",
50 | ),
51 | ),
52 | (
53 | "street",
54 | models.CharField(
55 | max_length=200, verbose_name="Area, Street, Sector, Village"
56 | ),
57 | ),
58 | ("landmark", models.CharField(max_length=100, verbose_name="Landmark")),
59 | ("town", models.CharField(max_length=100, verbose_name="Town/City")),
60 | (
61 | "state",
62 | models.CharField(
63 | choices=[
64 | ("AN", "Andaman and Nicobar Islands"),
65 | ("AP", "Andhra Pradesh"),
66 | ("AR", "Arunachal Pradesh"),
67 | ("AS", "Assam"),
68 | ("BR", "Bihar"),
69 | ("CG", "Chandigarh"),
70 | ("CH", "Chhattisgarh"),
71 | ("DN", "Dadra and Nagar Haveli"),
72 | ("DD", "Daman and Diu"),
73 | ("DL", "Delhi"),
74 | ("GA", "Goa"),
75 | ("GJ", "Gujarat"),
76 | ("HR", "Haryana"),
77 | ("HP", "Himachal Pradesh"),
78 | ("JK", "Jammu and Kashmir"),
79 | ("JH", "Jharkhand"),
80 | ("KA", "Karnataka"),
81 | ("KL", "Kerala"),
82 | ("LA", "Ladakh"),
83 | ("LD", "Lakshadweep"),
84 | ("MP", "Madhya Pradesh"),
85 | ("MH", "Maharashtra"),
86 | ("MN", "Manipur"),
87 | ("ML", "Meghalaya"),
88 | ("MZ", "Mizoram"),
89 | ("NL", "Nagaland"),
90 | ("OR", "Odisha"),
91 | ("PY", "Puducherry"),
92 | ("PB", "Punjab"),
93 | ("RJ", "Rajasthan"),
94 | ("SK", "Sikkim"),
95 | ("TN", "Tamil Nadu"),
96 | ("TS", "Telangana"),
97 | ("TR", "Tripura"),
98 | ("UP", "Uttar Pradesh"),
99 | ("UK", "Uttarakhand"),
100 | ("WB", "West Bengal"),
101 | ],
102 | max_length=100,
103 | verbose_name="State",
104 | ),
105 | ),
106 | (
107 | "default",
108 | models.BooleanField(
109 | default=False, verbose_name="Make this my default address"
110 | ),
111 | ),
112 | (
113 | "address_type",
114 | models.CharField(
115 | choices=[("Home", "Home"), ("Office", "Office")],
116 | max_length=100,
117 | verbose_name="Address Type",
118 | ),
119 | ),
120 | (
121 | "user",
122 | models.ForeignKey(
123 | on_delete=django.db.models.deletion.CASCADE,
124 | to=settings.AUTH_USER_MODEL,
125 | verbose_name="User",
126 | ),
127 | ),
128 | ],
129 | options={"abstract": False,},
130 | ),
131 | ]
132 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0004_brand.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 11:12
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0003_useraddress"),
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name="Brand",
15 | fields=[
16 | (
17 | "id",
18 | models.BigAutoField(
19 | auto_created=True,
20 | primary_key=True,
21 | serialize=False,
22 | verbose_name="ID",
23 | ),
24 | ),
25 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
26 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
27 | ("name", models.CharField(max_length=100, verbose_name="Brand Name")),
28 | ("logo", models.ImageField(upload_to="brands/logo")),
29 | ],
30 | options={"abstract": False,},
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0005_category.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 12:07
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0004_brand"),
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name="Category",
15 | fields=[
16 | (
17 | "id",
18 | models.BigAutoField(
19 | auto_created=True,
20 | primary_key=True,
21 | serialize=False,
22 | verbose_name="ID",
23 | ),
24 | ),
25 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
26 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
27 | (
28 | "name",
29 | models.CharField(max_length=100, verbose_name="Category Name"),
30 | ),
31 | ],
32 | options={"abstract": False,},
33 | ),
34 | ]
35 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0006_subcategory.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 12:09
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0005_category"),
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name="Subcategory",
15 | fields=[
16 | (
17 | "id",
18 | models.BigAutoField(
19 | auto_created=True,
20 | primary_key=True,
21 | serialize=False,
22 | verbose_name="ID",
23 | ),
24 | ),
25 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
26 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
27 | (
28 | "name",
29 | models.CharField(max_length=100, verbose_name="SubCategory Name"),
30 | ),
31 | ],
32 | options={"abstract": False,},
33 | ),
34 | ]
35 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0007_size.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 12:16
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0006_subcategory"),
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name="Size",
15 | fields=[
16 | (
17 | "id",
18 | models.BigAutoField(
19 | auto_created=True,
20 | primary_key=True,
21 | serialize=False,
22 | verbose_name="ID",
23 | ),
24 | ),
25 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
26 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
27 | ("name", models.CharField(max_length=100, verbose_name="Size")),
28 | ],
29 | options={"abstract": False,},
30 | ),
31 | ]
32 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0008_product.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 13:07
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("amazon_backend_api", "0007_size"),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name="Product",
16 | fields=[
17 | (
18 | "id",
19 | models.BigAutoField(
20 | auto_created=True,
21 | primary_key=True,
22 | serialize=False,
23 | verbose_name="ID",
24 | ),
25 | ),
26 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
27 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
28 | ("name", models.CharField(max_length=200, verbose_name="Product Name")),
29 | (
30 | "brand",
31 | models.ForeignKey(
32 | null=True,
33 | on_delete=django.db.models.deletion.SET_NULL,
34 | related_name="Brand_Name",
35 | to="amazon_backend_api.brand",
36 | ),
37 | ),
38 | (
39 | "category",
40 | models.ForeignKey(
41 | null=True,
42 | on_delete=django.db.models.deletion.SET_NULL,
43 | related_name="Category",
44 | to="amazon_backend_api.category",
45 | ),
46 | ),
47 | (
48 | "subcategory1",
49 | models.ForeignKey(
50 | null=True,
51 | on_delete=django.db.models.deletion.SET_NULL,
52 | related_name="SubCategory1",
53 | to="amazon_backend_api.subcategory",
54 | ),
55 | ),
56 | (
57 | "subcategory2",
58 | models.ForeignKey(
59 | null=True,
60 | on_delete=django.db.models.deletion.SET_NULL,
61 | related_name="SubCategory2",
62 | to="amazon_backend_api.subcategory",
63 | ),
64 | ),
65 | ],
66 | options={"abstract": False,},
67 | ),
68 | ]
69 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0009_productdetail.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 13:15
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("amazon_backend_api", "0008_product"),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name="ProductDetail",
16 | fields=[
17 | (
18 | "id",
19 | models.BigAutoField(
20 | auto_created=True,
21 | primary_key=True,
22 | serialize=False,
23 | verbose_name="ID",
24 | ),
25 | ),
26 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
27 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
28 | (
29 | "description",
30 | models.TextField(
31 | max_length=1000, verbose_name="Product Descriptions"
32 | ),
33 | ),
34 | (
35 | "mrp",
36 | models.DecimalField(
37 | decimal_places=2, max_digits=10, verbose_name="MRP"
38 | ),
39 | ),
40 | (
41 | "discount",
42 | models.DecimalField(
43 | decimal_places=2, max_digits=10, verbose_name="Discount"
44 | ),
45 | ),
46 | (
47 | "image1",
48 | models.ImageField(upload_to="products", verbose_name="Image 1"),
49 | ),
50 | (
51 | "image2",
52 | models.ImageField(upload_to="products", verbose_name="Image 2"),
53 | ),
54 | (
55 | "image3",
56 | models.ImageField(upload_to="products", verbose_name="Image 3"),
57 | ),
58 | (
59 | "product",
60 | models.ForeignKey(
61 | on_delete=django.db.models.deletion.CASCADE,
62 | related_name="product",
63 | to="amazon_backend_api.product",
64 | ),
65 | ),
66 | (
67 | "size",
68 | models.ManyToManyField(
69 | related_name="size", to="amazon_backend_api.size"
70 | ),
71 | ),
72 | ],
73 | options={"abstract": False,},
74 | ),
75 | ]
76 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0010_color.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 13:26
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0009_productdetail"),
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name="Color",
15 | fields=[
16 | (
17 | "id",
18 | models.BigAutoField(
19 | auto_created=True,
20 | primary_key=True,
21 | serialize=False,
22 | verbose_name="ID",
23 | ),
24 | ),
25 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
26 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
27 | ("name", models.CharField(max_length=100, verbose_name="Color Name")),
28 | ("code", models.CharField(max_length=100, verbose_name="Color Code")),
29 | ],
30 | options={"abstract": False,},
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0011_productdetail_color.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-01 13:28
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("amazon_backend_api", "0010_color"),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="productdetail",
16 | name="color",
17 | field=models.ForeignKey(
18 | null=True,
19 | on_delete=django.db.models.deletion.SET_NULL,
20 | related_name="Color",
21 | to="amazon_backend_api.color",
22 | ),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0012_productdetail_is_stock_productdetail_stocks.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-02 06:08
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("amazon_backend_api", "0011_productdetail_color"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="productdetail",
15 | name="is_stock",
16 | field=models.BooleanField(default=True, verbose_name="Stocks Avaliable"),
17 | ),
18 | migrations.AddField(
19 | model_name="productdetail",
20 | name="stocks",
21 | field=models.IntegerField(default=100, verbose_name="Number of Stocks"),
22 | preserve_default=False,
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/0013_cart.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.1.5 on 2023-02-02 10:44
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 | dependencies = [
11 | ("amazon_backend_api", "0012_productdetail_is_stock_productdetail_stocks"),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name="Cart",
17 | fields=[
18 | (
19 | "id",
20 | models.BigAutoField(
21 | auto_created=True,
22 | primary_key=True,
23 | serialize=False,
24 | verbose_name="ID",
25 | ),
26 | ),
27 | ("created_at", models.DateTimeField(auto_now_add=True, null=True)),
28 | ("updated_at", models.DateTimeField(auto_now=True, null=True)),
29 | ("quantity", models.IntegerField(default=1, verbose_name="Quantity")),
30 | (
31 | "product",
32 | models.ForeignKey(
33 | on_delete=django.db.models.deletion.CASCADE,
34 | related_name="Product",
35 | to="amazon_backend_api.productdetail",
36 | ),
37 | ),
38 | (
39 | "user",
40 | models.ForeignKey(
41 | on_delete=django.db.models.deletion.CASCADE,
42 | related_name="AmazonUser",
43 | to=settings.AUTH_USER_MODEL,
44 | ),
45 | ),
46 | ],
47 | options={"abstract": False,},
48 | ),
49 | ]
50 |
--------------------------------------------------------------------------------
/amazon_backend_api/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amazon_backend_api/migrations/__init__.py
--------------------------------------------------------------------------------
/amazon_backend_api/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from amazon_backend_api.manager import AmazonuserManager
3 | from django.contrib.auth.models import AbstractUser
4 | from django.utils.translation import gettext_lazy as _
5 | from amazon_backend_api.api.utils import INDIAN_STATES
6 |
7 |
8 | STATE_CHOICES = ((state, INDIAN_STATES.get(state)) for state in INDIAN_STATES)
9 |
10 |
11 | class Amazonuser(AbstractUser):
12 | username = None
13 | first_name = None
14 | last_name = None
15 | email = models.EmailField(_("email address"), unique=True)
16 | full_name = models.CharField(_("full name"), max_length=100)
17 |
18 | USERNAME_FIELD = "email"
19 | REQUIRED_FIELDS = []
20 |
21 | objects = AmazonuserManager()
22 |
23 | def __str__(self):
24 | return self.email
25 |
26 |
27 | class BaseModel(models.Model):
28 |
29 | created_at = models.DateTimeField(auto_now_add=True, null=True)
30 | updated_at = models.DateTimeField(auto_now=True, null=True)
31 |
32 | class Meta:
33 | abstract = True
34 |
35 |
36 | class UserAddress(BaseModel):
37 |
38 | user = models.ForeignKey(Amazonuser, on_delete=models.CASCADE, verbose_name="User")
39 | country = models.CharField(
40 | verbose_name="Country", choices=(("India", "India"),), max_length=100
41 | )
42 | full_name = models.CharField(
43 | verbose_name="Full name (First and last name)", max_length=100
44 | )
45 | mobile_number = models.IntegerField(verbose_name="Mobile number")
46 | pincode = models.IntegerField(verbose_name="Pincode")
47 | flat = models.CharField(
48 | verbose_name="Flat, House no., Building, Company, Apartment", max_length=200
49 | )
50 | street = models.CharField(
51 | verbose_name="Area, Street, Sector, Village", max_length=200
52 | )
53 | landmark = models.CharField(verbose_name="Landmark", max_length=100)
54 | town = models.CharField(verbose_name="Town/City", max_length=100)
55 | state = models.CharField(
56 | verbose_name="State", choices=STATE_CHOICES, max_length=100
57 | )
58 | default = models.BooleanField(
59 | verbose_name="Make this my default address", default=False
60 | )
61 | address_type = models.CharField(
62 | verbose_name="Address Type",
63 | max_length=100,
64 | choices=(("Home", "Home"), ("Office", "Office")),
65 | )
66 |
67 | def __str__(self):
68 | return str(f"{self.full_name} Address")
69 |
70 |
71 | class Brand(BaseModel):
72 | name = models.CharField(verbose_name="Brand Name", max_length=100)
73 | logo = models.ImageField(upload_to="brands/logo")
74 |
75 | def __str__(self):
76 | return str(f"{self.name}")
77 |
78 |
79 | class Category(BaseModel):
80 | name = models.CharField(verbose_name="Category Name", max_length=100)
81 |
82 | def __str__(self):
83 | return str(f"{self.name}")
84 |
85 |
86 | class Subcategory(BaseModel):
87 | name = models.CharField(verbose_name="SubCategory Name", max_length=100)
88 |
89 | def __str__(self):
90 | return str(f"{self.name}")
91 |
92 |
93 | class Size(BaseModel):
94 | name = models.CharField(verbose_name="Size", max_length=100)
95 |
96 | def __str__(self):
97 | return str(f"{self.name}")
98 |
99 |
100 | class Color(BaseModel):
101 | name = models.CharField(verbose_name="Color Name", max_length=100)
102 | code = models.CharField(verbose_name="Color Code", max_length=100)
103 |
104 | def __str__(self):
105 | return str(f"{self.name}")
106 |
107 |
108 | class Product(BaseModel):
109 | name = models.CharField(verbose_name="Product Name", max_length=200)
110 | brand = models.ForeignKey(
111 | Brand, on_delete=models.SET_NULL, related_name="Brand_Name", null=True
112 | )
113 | category = models.ForeignKey(
114 | Category, on_delete=models.SET_NULL, related_name="Category", null=True
115 | )
116 | subcategory1 = models.ForeignKey(
117 | Subcategory, on_delete=models.SET_NULL, related_name="SubCategory1", null=True
118 | )
119 | subcategory2 = models.ForeignKey(
120 | Subcategory, on_delete=models.SET_NULL, related_name="SubCategory2", null=True
121 | )
122 |
123 | def __str__(self) -> str:
124 | return str(f"{self.name}")
125 |
126 |
127 | class ProductDetail(BaseModel):
128 | product = models.ForeignKey(
129 | Product, on_delete=models.CASCADE, related_name="product"
130 | )
131 | size = models.ManyToManyField(Size, related_name="size")
132 | color = models.ForeignKey(
133 | Color, on_delete=models.SET_NULL, null=True, related_name="Color"
134 | )
135 | description = models.TextField(verbose_name="Product Descriptions", max_length=1000)
136 | mrp = models.DecimalField(verbose_name="MRP", decimal_places=2, max_digits=10)
137 | discount = models.DecimalField(
138 | verbose_name="Discount", decimal_places=2, max_digits=10
139 | )
140 | stocks = models.IntegerField(verbose_name="Number of Stocks")
141 | is_stock = models.BooleanField(verbose_name="Stocks Avaliable", default=True)
142 | image1 = models.ImageField(upload_to="products", verbose_name="Image 1")
143 | image2 = models.ImageField(upload_to="products", verbose_name="Image 2")
144 | image3 = models.ImageField(upload_to="products", verbose_name="Image 3")
145 |
146 | def __str__(self) -> str:
147 | return str(f"{self.product} Details")
148 |
149 |
150 | class Cart(BaseModel):
151 | user = models.ForeignKey(
152 | Amazonuser, on_delete=models.CASCADE, related_name="AmazonUser"
153 | )
154 | product = models.ForeignKey(
155 | ProductDetail, on_delete=models.CASCADE, related_name="Product"
156 | )
157 | quantity = models.IntegerField(verbose_name="Quantity", default=1)
158 |
159 | def __str__(self):
160 | return str(f"{self.product}")
161 |
--------------------------------------------------------------------------------
/amazon_backend_api/tests.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 | from rest_framework import status
3 | from rest_framework.test import APITestCase
4 | from amazon_backend_api.models import Amazonuser
5 | from django.contrib.auth.hashers import make_password
6 |
7 |
8 | class TestRegistration(APITestCase):
9 | """
10 | This will handle Registration Test Case
11 | """
12 |
13 | def setUp(self):
14 | self.url = reverse("amz-user-register")
15 |
16 | def test_registration(self):
17 | """
18 | This will test registration
19 | """
20 |
21 | data = {
22 | "full_name": "Aashish Kumar",
23 | "email": "wek@gmail.com",
24 | "password": "bwfjjwje",
25 | }
26 |
27 | response = self.client.post(self.url, data=data)
28 |
29 | self.assertEqual(
30 | response.status_code, status.HTTP_201_CREATED, msg="test_registration"
31 | )
32 |
33 | def test_without_data_registration(self):
34 | """
35 | This will test registration without data
36 | """
37 |
38 | response = self.client.post(self.url)
39 | self.assertEqual(
40 | response.status_code,
41 | status.HTTP_400_BAD_REQUEST,
42 | msg="test_without_data_registration_statuscode",
43 | )
44 | self.assertEqual(
45 | response.data.get("data").get("full_name")[0],
46 | "This field is required.",
47 | msg="test_without_fullname_registration_data_fullname",
48 | )
49 | self.assertEqual(
50 | response.data.get("data").get("email")[0],
51 | "This field is required.",
52 | msg="test_without_fullname_registration_data_email",
53 | )
54 | self.assertEqual(
55 | response.data.get("data").get("password")[0],
56 | "This field is required.",
57 | msg="test_without_fullname_registration_data_password",
58 | )
59 |
60 | def test_without_fullname_registration(self):
61 | """
62 | This will test registration without fullname
63 | """
64 |
65 | data = {"email": "wek@gmail.com", "password": "bwfjjwje"}
66 | response = self.client.post(self.url, data=data)
67 | self.assertEqual(
68 | response.status_code,
69 | status.HTTP_400_BAD_REQUEST,
70 | msg="test_without_fullname_registration_statuscode",
71 | )
72 | self.assertEqual(
73 | response.data.get("data").get("full_name")[0],
74 | "This field is required.",
75 | msg="test_without_fullname_registration_data",
76 | )
77 |
78 | def test_without_email_registration(self):
79 | """
80 | This will test registration without email
81 | """
82 |
83 | data = {"full_name": "Aashish Kumar", "password": "bwfjjwje"}
84 | response = self.client.post(self.url, data=data)
85 | self.assertEqual(
86 | response.status_code,
87 | status.HTTP_400_BAD_REQUEST,
88 | msg="test_without_email_registration_statuscode",
89 | )
90 | self.assertEqual(
91 | response.data.get("data").get("email")[0],
92 | "This field is required.",
93 | msg="test_without_email_registration_data",
94 | )
95 |
96 | def test_without_password_registration(self):
97 | """
98 | This will test registration without password
99 | """
100 |
101 | data = {
102 | "full_name": "Aashish Kumar",
103 | "email": "wek@gmail.com",
104 | }
105 | response = self.client.post(self.url, data=data)
106 | self.assertEqual(
107 | response.status_code,
108 | status.HTTP_400_BAD_REQUEST,
109 | msg="test_without_password_registration_statuscode",
110 | )
111 | self.assertEqual(
112 | response.data.get("data").get("password")[0],
113 | "This field is required.",
114 | msg="test_without_password_registration_data",
115 | )
116 |
117 | def test_invalid_email_registration(self):
118 | """
119 | This will test invalid email address for registration...
120 | """
121 |
122 | data = {
123 | "full_name": "Aashish Kumar",
124 | "email": "wek@gmail.",
125 | "password": "bwfjjwje",
126 | }
127 |
128 | response = self.client.post(self.url, data=data)
129 |
130 | self.assertEqual(
131 | response.status_code,
132 | status.HTTP_400_BAD_REQUEST,
133 | msg="test_invalid_email_registration_statuscode",
134 | )
135 | self.assertEqual(
136 | response.data.get("data").get("email")[0],
137 | "Enter a valid email address.",
138 | msg="test_invalid_emai_registration_data",
139 | )
140 |
141 | def test_exists_email_registration(self):
142 | """
143 | This will test exist email address for registration...
144 | """
145 |
146 | data = {
147 | "full_name": "Aashish Kumar",
148 | "email": "whghg@gmail.com",
149 | "password": "bwfjjwje",
150 | }
151 |
152 | Amazonuser.objects.create(
153 | full_name=data.get("full_name"),
154 | email=data.get("email"),
155 | password=data.get("password"),
156 | )
157 | response = self.client.post(self.url, data=data)
158 |
159 | self.assertEqual(
160 | response.status_code,
161 | status.HTTP_400_BAD_REQUEST,
162 | msg="test_exists_email_registration_statuscode",
163 | )
164 | self.assertEqual(
165 | response.data.get("data").get("email")[0],
166 | "user with this email address already exists.",
167 | msg="test_exists_email_registration_data",
168 | )
169 |
170 |
171 | class TestLogin(APITestCase):
172 | """
173 | This will handle login testcases
174 | """
175 |
176 | def setUp(self):
177 | self.url = reverse("amz-user-sign-in")
178 |
179 | def test_login(self):
180 | """
181 | This will test successfull login
182 | """
183 | data = {
184 | "full_name": "Aashish Kumar",
185 | "email": "whghg@gmail.com",
186 | "password": "bwfjjwje",
187 | }
188 |
189 | Amazonuser.objects.create(
190 | full_name=data.get("full_name"),
191 | email=data.get("email"),
192 | password=make_password(data.get("password")),
193 | )
194 |
195 | response = self.client.post(self.url, data=data)
196 | self.assertEqual(
197 | response.status_code,
198 | status.HTTP_200_OK,
199 | msg="test_login_successfull_statuscode",
200 | )
201 |
202 | def test_login_without_data(self):
203 | """
204 | This will test login without data from client
205 | """
206 |
207 | response = self.client.post(self.url)
208 | self.assertEqual(
209 | response.status_code,
210 | status.HTTP_400_BAD_REQUEST,
211 | msg="test_login_without_data_statuscode",
212 | )
213 |
214 | self.assertEqual(
215 | response.data.get("data").get("email")[0],
216 | "This field is required.",
217 | msg="test_login_without_data_DATA_email",
218 | )
219 |
220 | self.assertEqual(
221 | response.data.get("data").get("password")[0],
222 | "This field is required.",
223 | msg="test_login_without_data_DATA_password",
224 | )
225 |
226 | def test_login_with_invalid_credentials(self):
227 | """
228 | This will test login with invalid credentials
229 | """
230 |
231 | """wrong credentials"""
232 | data = {"email": "whghg@gmail.com", "password": "bwfjjwje"}
233 |
234 | response = self.client.post(self.url, data=data)
235 | self.assertEqual(
236 | response.status_code,
237 | status.HTTP_401_UNAUTHORIZED,
238 | msg="test_login_with_invalid_credentials_statuscode",
239 | )
240 | self.assertEqual(
241 | response.data.get("message"),
242 | "Invalid Email or Password",
243 | msg="test_login_with_invalid_credentials_message",
244 | )
245 |
246 | def test_login_with_empty_data(self):
247 | """
248 | This will test login with empty data from client
249 | """
250 |
251 | """empty data"""
252 | data = {"email": "", "password": ""}
253 |
254 | response = self.client.post(self.url, data=data)
255 | self.assertEqual(
256 | response.status_code,
257 | status.HTTP_400_BAD_REQUEST,
258 | msg="test_login_with_empty_data_statuscode",
259 | )
260 |
261 | self.assertEqual(
262 | response.data.get("data").get("email")[0],
263 | "This field may not be blank.",
264 | msg="test_login_with_empty_data_DATA_email",
265 | )
266 |
267 | self.assertEqual(
268 | response.data.get("data").get("password")[0],
269 | "This field may not be blank.",
270 | msg="test_login_with_empty_data_DATA_password",
271 | )
272 |
--------------------------------------------------------------------------------
/amazon_backend_api/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | # Create your views here.
4 |
--------------------------------------------------------------------------------
/amz-media/brands/logo/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/brands/logo/download.png
--------------------------------------------------------------------------------
/amz-media/brands/logo/hrx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/brands/logo/hrx.png
--------------------------------------------------------------------------------
/amz-media/products/519I05HaHjL._SX569._SX._UX._SY._UY_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/products/519I05HaHjL._SX569._SX._UX._SY._UY_.jpg
--------------------------------------------------------------------------------
/amz-media/products/51raYlT-AUL._UX569_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/products/51raYlT-AUL._UX569_.jpg
--------------------------------------------------------------------------------
/amz-media/products/61UagAR6IcL._UX569_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/products/61UagAR6IcL._UX569_.jpg
--------------------------------------------------------------------------------
/amz-media/products/61UagAR6IcL._UX569__xI8CtqU.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/products/61UagAR6IcL._UX569__xI8CtqU.jpg
--------------------------------------------------------------------------------
/amz-media/products/61mUSVo0b7S._SX569._SX._UX._SY._UY_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/products/61mUSVo0b7S._SX569._SX._UX._SY._UY_.jpg
--------------------------------------------------------------------------------
/amz-media/products/71mBMP1WTsL._SX569._SX._UX._SY._UY_.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/amz-media/products/71mBMP1WTsL._SX569._SX._UX._SY._UY_.jpg
--------------------------------------------------------------------------------
/backend/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aashishkumar123/amazon-backend/da4baab5479746141dd66cc4741813d52fed34c8/backend/__init__.py
--------------------------------------------------------------------------------
/backend/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for backend 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', 'backend.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/backend/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for backend project.
3 |
4 | Generated by 'django-admin startproject' using Django 3.2.
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 | from datetime import timedelta
15 |
16 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
17 | BASE_DIR = Path(__file__).resolve().parent.parent
18 |
19 |
20 | # Quick-start development settings - unsuitable for production
21 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = 'django-insecure-a104wyjj=x2i71z6$b7f1aq(xx$nd1^2h5ou&r^3h$bl*zkb5g'
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = True
28 |
29 | ALLOWED_HOSTS = []
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 | 'rest_framework',
42 | 'rest_framework_simplejwt',
43 | 'drf_yasg',
44 | 'corsheaders',
45 | 'amazon_backend_api.apps.AmazonBackendApiConfig',
46 | ]
47 |
48 | MIDDLEWARE = [
49 | 'django.middleware.security.SecurityMiddleware',
50 | 'django.contrib.sessions.middleware.SessionMiddleware',
51 | 'corsheaders.middleware.CorsMiddleware',
52 | 'django.middleware.common.CommonMiddleware',
53 | 'django.middleware.csrf.CsrfViewMiddleware',
54 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
55 | 'django.contrib.messages.middleware.MessageMiddleware',
56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
57 | ]
58 |
59 | ROOT_URLCONF = 'backend.urls'
60 |
61 | TEMPLATES = [
62 | {
63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
64 | 'DIRS': [],
65 | 'APP_DIRS': True,
66 | 'OPTIONS': {
67 | 'context_processors': [
68 | 'django.template.context_processors.debug',
69 | 'django.template.context_processors.request',
70 | 'django.contrib.auth.context_processors.auth',
71 | 'django.contrib.messages.context_processors.messages',
72 | ],
73 | },
74 | },
75 | ]
76 |
77 | WSGI_APPLICATION = 'backend.wsgi.application'
78 |
79 |
80 | # Database
81 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
82 |
83 | DATABASES = {
84 | 'default': {
85 | 'ENGINE': 'django.db.backends.postgresql',
86 | 'NAME': 'amazon-backend-db',
87 | 'USER': 'postgres',
88 | 'PASSWORD': 'aakumar123',
89 | 'HOST': 'localhost',
90 | 'PORT': '5432',
91 | }
92 | }
93 |
94 |
95 | # Password validation
96 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
97 |
98 | AUTH_PASSWORD_VALIDATORS = [
99 | {
100 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
101 | },
102 | {
103 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
104 | },
105 | {
106 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
107 | },
108 | {
109 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
110 | },
111 | ]
112 |
113 |
114 | # Internationalization
115 | # https://docs.djangoproject.com/en/3.2/topics/i18n/
116 |
117 | LANGUAGE_CODE = 'en-us'
118 |
119 | TIME_ZONE = 'UTC'
120 |
121 | USE_I18N = True
122 |
123 | USE_L10N = True
124 |
125 | USE_TZ = True
126 |
127 |
128 | # Static files (CSS, JavaScript, Images)
129 | # https://docs.djangoproject.com/en/3.2/howto/static-files/
130 |
131 | STATIC_URL = '/static/'
132 |
133 | # Default primary key field type
134 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
135 |
136 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
137 |
138 |
139 | #REGISTER CUSTOM USER
140 | AUTH_USER_MODEL = 'amazon_backend_api.Amazonuser'
141 |
142 |
143 | #REST FRAMEWORK SETTINGS
144 | REST_FRAMEWORK = {
145 | 'DEFAULT_AUTHENTICATION_CLASSES': (
146 | 'rest_framework_simplejwt.authentication.JWTAuthentication',
147 | )
148 | }
149 |
150 | #SIMPLE JWT SETTINGS
151 | SIMPLE_JWT = {
152 | 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
153 | 'REFRESH_TOKEN_LIFETIME': timedelta(days=365),
154 | 'ROTATE_REFRESH_TOKENS': False,
155 | 'BLACKLIST_AFTER_ROTATION': False,
156 | 'UPDATE_LAST_LOGIN': False,
157 |
158 | 'ALGORITHM': 'HS256',
159 | 'SIGNING_KEY': SECRET_KEY,
160 | 'VERIFYING_KEY': None,
161 | 'AUDIENCE': None,
162 | 'ISSUER': None,
163 | 'JWK_URL': None,
164 | 'LEEWAY': 0,
165 |
166 | 'AUTH_HEADER_TYPES': ('Bearer',),
167 | 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
168 | 'USER_ID_FIELD': 'email',
169 | 'USER_ID_CLAIM': 'email',
170 | 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
171 |
172 | 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
173 | 'TOKEN_TYPE_CLAIM': 'token_type',
174 | 'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
175 |
176 | 'JTI_CLAIM': 'jti',
177 |
178 | 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
179 | 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
180 | 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
181 | }
182 |
183 | #MEDIA SETTINGS
184 | MEDIA_URL = '/amz-media/'
185 | MEDIA_ROOT = BASE_DIR/'amz-media'
186 |
187 | #CORS HEADERS SETTINGS
188 | CORS_ALLOWED_ORIGINS = [
189 | 'http://localhost:3000'
190 | ]
191 |
--------------------------------------------------------------------------------
/backend/urls.py:
--------------------------------------------------------------------------------
1 | """backend 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 | from django.conf import settings
19 | from django.conf.urls.static import static
20 |
21 |
22 | urlpatterns = [
23 | path("admin/", admin.site.urls),
24 | path("api/amz/", include("amazon_backend_api.api.urls")),
25 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
26 |
--------------------------------------------------------------------------------
/backend/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for backend 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', 'backend.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.9'
2 |
3 | services:
4 | django:
5 | image: amazon-api:0.0.1
6 | build: .
7 | ports:
8 | - "8000:8000"
9 |
--------------------------------------------------------------------------------
/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', 'backend.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.6.0
2 | black==23.1.0
3 | certifi==2022.12.7
4 | charset-normalizer==3.0.1
5 | click==8.1.3
6 | coreapi==2.3.3
7 | coreschema==0.0.4
8 | Django==4.1.5
9 | django-cors-headers==3.13.0
10 | djangorestframework==3.14.0
11 | djangorestframework-simplejwt==5.2.2
12 | drf-yasg==1.21.4
13 | flake8==6.0.0
14 | idna==3.4
15 | inflection==0.5.1
16 | itypes==1.2.0
17 | Jinja2==3.1.2
18 | MarkupSafe==2.1.2
19 | mccabe==0.7.0
20 | mypy-extensions==1.0.0
21 | packaging==23.0
22 | pathspec==0.11.0
23 | Pillow==9.4.0
24 | platformdirs==3.0.0
25 | psycopg2-binary==2.9.5
26 | pycodestyle==2.10.0
27 | pyflakes==3.0.1
28 | PyJWT==2.6.0
29 | pytz==2022.7.1
30 | requests==2.28.2
31 | ruamel.yaml==0.17.21
32 | ruamel.yaml.clib==0.2.7
33 | sqlparse==0.4.3
34 | tomli==2.0.1
35 | typing_extensions==4.4.0
36 | uritemplate==4.1.1
37 | urllib3==1.26.14
38 |
--------------------------------------------------------------------------------