11from django .conf import settings
22from django .contrib .auth .models import AbstractUser
3+ from django .core .validators import MaxValueValidator , MinValueValidator
34from django .db import models
45
56
7+ class TimestampedModel (models .Model ):
8+ created_at = models .DateTimeField (auto_now_add = True )
9+ updated_at = models .DateTimeField (auto_now = True )
10+
11+ class Meta :
12+ abstract = True
13+
14+
615class User (AbstractUser ):
716 ROLE_CHOICES = [
817 ("user" , "User" ),
@@ -22,7 +31,7 @@ def __str__(self):
2231 return str (self .name )
2332
2433
25- class Profile (models . Model ):
34+ class Profile (TimestampedModel ):
2635 PROFILE_STATUS = [
2736 ("inactive" , "Inactive" ),
2837 ("pending" , "Pending" ),
@@ -51,14 +60,92 @@ def __str__(self):
5160 return str (self .user )
5261
5362
54- class Review (models .Model ):
63+ class Category (TimestampedModel ):
64+ name = models .CharField (max_length = 100 , unique = True )
65+
66+ def __str__ (self ):
67+ return self .name
68+
69+
70+ class Brand (TimestampedModel ):
71+ name = models .CharField (max_length = 100 , unique = True )
72+ category = models .ForeignKey (
73+ Category ,
74+ on_delete = models .SET_NULL ,
75+ null = True ,
76+ blank = True ,
77+ related_name = "brands" ,
78+ )
79+
80+ def __str__ (self ):
81+ return str (self .name )
82+
83+
84+ class Product (TimestampedModel ):
85+ product_name = models .CharField (max_length = 255 )
86+ description = models .TextField (blank = True , default = "" )
87+ price = models .DecimalField (max_digits = 10 , decimal_places = 2 )
88+ tags = models .ManyToManyField (Tag , blank = True )
89+ status = models .CharField (
90+ choices = [("stock" , "Stock" ), ("out_of_stock" , "Out of Stock" )], max_length = 20
91+ )
92+ technical_specifications = models .JSONField (blank = True , null = True )
93+ brand = models .ForeignKey (
94+ Brand ,
95+ on_delete = models .CASCADE ,
96+ null = True ,
97+ blank = True ,
98+ related_name = "products" ,
99+ )
100+
101+ def __str__ (self ):
102+ return str (self .product_name )
103+
104+ @property
105+ def average_rating (self ):
106+ reviews = self .reviews .all ()
107+ if reviews .exists ():
108+ return round (sum ([r .rating for r in reviews ]) / reviews .count (), 2 )
109+ return 0
110+
111+
112+ class ProductImage (models .Model ):
113+ product = models .ForeignKey (
114+ Product , on_delete = models .CASCADE , related_name = "images"
115+ )
116+ image = models .ImageField (upload_to = "products/gallery/" )
117+
118+ def __str__ (self ):
119+ return f"Image for { self .product .product_name } "
120+
121+
122+ class ProductReview (TimestampedModel ):
123+ product = models .ForeignKey (
124+ Product , on_delete = models .CASCADE , related_name = "reviews"
125+ )
126+ user = models .ForeignKey (
127+ User , on_delete = models .CASCADE , related_name = "user_reviews"
128+ )
129+ rating = models .PositiveIntegerField (
130+ validators = [MinValueValidator (1 ), MaxValueValidator (5 )]
131+ )
132+ review_text = models .TextField (blank = True )
133+ image = models .ImageField (upload_to = "reviews/" , blank = True , null = True )
134+
135+ class Meta :
136+ unique_together = ("user" , "product" ) # One review per user
137+
138+ def __str__ (self ):
139+ return f"{ self .user .username } - { self .product .product_name } "
140+
141+
142+ class Review (TimestampedModel ):
55143 technician = models .ForeignKey (
56144 Profile , on_delete = models .CASCADE , related_name = "reviews"
57145 )
58146 reviewer = models .ForeignKey (settings .AUTH_USER_MODEL , on_delete = models .CASCADE )
59147 rating = models .PositiveSmallIntegerField ()
60148 review_text = models .TextField ()
61- created_at = models .DateTimeField (auto_now_add = True )
62149
63150 def __str__ (self ):
64151 return str (self .technician ) + " - " + str (self .rating )
0 commit comments