Skip to content

Commit 53b1180

Browse files
Re-structured applications
1 parent 9147275 commit 53b1180

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1032
-374
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.venv
22
.idea
3-
Notes
3+
Notes
4+
.env

api/Pagination.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

api/admin.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22

3-
from .models import User, Profile, Category, Product
3+
from .models import User, Profile
44

55

66
@admin.register(User)
@@ -16,19 +16,3 @@ class ProfileAdmin(admin.ModelAdmin):
1616
list_display = ('user', 'location', 'birth_date')
1717
search_fields = ('user__username', 'location')
1818
list_filter = ('birth_date',)
19-
20-
21-
@admin.register(Category)
22-
class CategoryAdmin(admin.ModelAdmin):
23-
list_display = ('name', 'slug')
24-
search_fields = ('name',)
25-
prepopulated_fields = {'slug': ('name',)}
26-
27-
28-
@admin.register(Product)
29-
class ProductAdmin(admin.ModelAdmin):
30-
list_display = ('name', 'price', 'stock', 'category', 'slug')
31-
list_filter = ('category', 'tags', 'price', 'stock')
32-
search_fields = ('name', 'description', 'category__name', 'tags__name')
33-
prepopulated_fields = {'slug': ('name',)}
34-
autocomplete_fields = ('category',)

api/models.py

Lines changed: 1 addition & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import uuid
2-
31
from django.contrib.auth.models import AbstractUser
42
from django.db import models
5-
from django.utils.text import slugify
6-
from taggit.managers import TaggableManager
73

8-
from .utils import product_upload_to_unique, profile_upload_to_unique
4+
from .utils import profile_upload_to_unique
95

106

117
class User(AbstractUser):
@@ -29,120 +25,3 @@ class Meta:
2925

3026
def __str__(self):
3127
return f'{self.user.username} Profile'
32-
33-
34-
class Category(models.Model):
35-
name = models.CharField(max_length=255)
36-
slug = models.SlugField(max_length=255, unique=True)
37-
38-
class Meta:
39-
verbose_name = "Category"
40-
verbose_name_plural = "Categories"
41-
indexes = [
42-
models.Index(fields=['name']),
43-
]
44-
ordering = ["name"]
45-
46-
def __str__(self):
47-
return f"Category: {self.name}"
48-
49-
50-
class Product(models.Model):
51-
product_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
52-
name = models.CharField(max_length=255)
53-
slug = models.SlugField(max_length=255, unique=True)
54-
description = models.TextField()
55-
price = models.DecimalField(max_digits=10, decimal_places=2)
56-
stock = models.IntegerField()
57-
image = models.ImageField(
58-
null=True,
59-
blank=True,
60-
upload_to=product_upload_to_unique
61-
)
62-
category = models.ForeignKey(
63-
Category,
64-
related_name="products",
65-
on_delete=models.CASCADE,
66-
)
67-
tags = TaggableManager()
68-
69-
class Meta:
70-
verbose_name = "Product"
71-
verbose_name_plural = "Products"
72-
indexes = [
73-
models.Index(fields=['slug']),
74-
models.Index(fields=['name']),
75-
models.Index(fields=['category']),
76-
]
77-
ordering = ["name"]
78-
79-
def save(self, *args, **kwargs):
80-
# Auto-generate slug if not set or name changes
81-
if not self.slug or self.name != self.__class__.objects.get(pk=self.pk).name:
82-
self.slug = slugify(self.name)
83-
super().save(*args, **kwargs)
84-
85-
def __str__(self):
86-
return f"Product: {self.name} (ID: {self.product_id})"
87-
88-
89-
class Order(models.Model):
90-
class Status(models.TextChoices):
91-
PENDING = 'PE', 'Pending'
92-
COMPLETED = 'CO', 'Completed'
93-
CANCELLED = 'CA', 'Cancelled'
94-
95-
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
96-
quantity = models.IntegerField()
97-
order_date = models.DateTimeField(auto_now_add=True)
98-
status = models.CharField(max_length=10, choices=Status.choices, default=Status.PENDING)
99-
100-
class Meta:
101-
verbose_name = "Order"
102-
verbose_name_plural = "Orders"
103-
indexes = [
104-
models.Index(fields=['user']),
105-
models.Index(fields=['order_date']),
106-
]
107-
ordering = ["-order_date"]
108-
109-
@property
110-
def total_price(self):
111-
"""
112-
Calculate the total price of the order.
113-
114-
Returns:
115-
Decimal: The total price, which is the sum of all order items' prices.
116-
"""
117-
return sum(item.price for item in self.items.all())
118-
119-
def __str__(self):
120-
return f"Order: {self.id} by {self.user.username if self.user else 'Deleted User'}"
121-
122-
123-
class OrderItem(models.Model):
124-
order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
125-
product = models.ForeignKey(Product, on_delete=models.CASCADE)
126-
quantity = models.PositiveSmallIntegerField()
127-
128-
class Meta:
129-
verbose_name = "Order Item"
130-
verbose_name_plural = "Order Items"
131-
indexes = [
132-
models.Index(fields=['order']),
133-
models.Index(fields=['product']),
134-
]
135-
ordering = ["order"]
136-
137-
@property
138-
def price(self):
139-
"""
140-
Calculate the total price for the order item.
141-
142-
Returns:
143-
Decimal: The total price, which is the product of the item's price and quantity.
144-
"""
145-
return self.product.price * self.quantity
146-
147-
def __str__(self):
148-
return f"Order Item: {self.product.name} (Order ID: {self.order.id})"

api/serializers.py

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from rest_framework import serializers
22

3-
from .models import Category, Product, User, Profile, Order, OrderItem
3+
from .models import User, Profile
44

55

66
class UserSerializer(serializers.ModelSerializer):
@@ -14,75 +14,3 @@ class Meta:
1414
class Meta:
1515
model = User
1616
fields = ['username', 'profile', 'first_name', 'last_name']
17-
18-
19-
class CategorySerializer(serializers.ModelSerializer):
20-
class Meta:
21-
model = Category
22-
fields = ['name', 'slug']
23-
extra_kwargs = {'slug': {'read_only': True}} # Make the slug field read-only
24-
25-
26-
class ProductSerializer(serializers.ModelSerializer):
27-
category = CategorySerializer()
28-
29-
tags = serializers.ListField(
30-
child=serializers.CharField(),
31-
source='tags.names',
32-
required=False,
33-
)
34-
35-
def to_internal_value(self, data):
36-
if self.instance is None and 'category' not in data:
37-
raise serializers.ValidationError(
38-
{'category': 'This field is required when creating a product.'}
39-
)
40-
return super().to_internal_value(data)
41-
42-
def create(self, validated_data):
43-
# Custom create method to handle tags
44-
instance = super().create(**validated_data) # Create the Product instance
45-
tags = validated_data.pop('tags', None) # Extract tags from validated data
46-
if tags:
47-
instance.tags.set(*tags) # Assign tags to the product
48-
return instance
49-
50-
def update(self, instance, validated_data):
51-
# Custom update method to handle tags
52-
tags = validated_data.pop('tags', None) # Extract tags from validated data
53-
if tags:
54-
instance.tags.set(*tags) # Replace existing tags with new ones
55-
else:
56-
instance.tags.clear() # Clear tags if none are provided
57-
58-
return super().update(instance, validated_data)
59-
60-
class Meta:
61-
model = Product
62-
fields = [
63-
'product_id',
64-
'name',
65-
'slug',
66-
'description',
67-
'price',
68-
'stock',
69-
'image',
70-
'category',
71-
'tags'
72-
]
73-
74-
75-
class OrderSerializer(serializers.ModelSerializer):
76-
class OrderItemSerializer(serializers.ModelSerializer):
77-
product = ProductSerializer(many=False, read_only=True)
78-
79-
class Meta:
80-
model = OrderItem
81-
fields = ['product', 'quantity', 'price']
82-
83-
order_items = OrderItemSerializer(many=True, read_only=True)
84-
85-
class Meta:
86-
model = Order
87-
fields = ['user', 'quantity', 'order_date', 'order_items', 'total_price']
88-
read_only_fields = ['user', 'order_date']

api/utils.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
1-
import os
2-
import uuid
1+
from ecommerce_api.utils.file_handling import upload_to_unique
32

43

5-
def upload_to_uniqe(instance, filename, directory):
6-
ext = filename.split('.')[-1]
7-
return os.path.join(f"{directory}/", f"{uuid.uuid4()}.{ext}")
8-
9-
10-
def product_upload_to_unique(instance, filename):
11-
"""
12-
Generate a unique file name for the product image.
13-
:param instance:
14-
:param filename:
15-
:return:
16-
"""
17-
return upload_to_uniqe(instance, filename, directory="products/")
18-
194
def profile_upload_to_unique(instance, filename):
205
"""
216
Generate a unique file name for the profile image.
227
:param instance:
238
:param filename:
249
:return:
2510
"""
26-
return upload_to_uniqe(instance, filename, directory="profiles/")
11+
return upload_to_unique(instance, filename, directory="profiles/")

0 commit comments

Comments
 (0)