7
\$\begingroup\$

I am planning to develop a virtual shopping mall where stores of any kind can be registered, such as in a physical shopping mall. First I want to develop an efficient and effective database modeling for products and stores only. I wanted it be very flexible and user friendly. Here is the model design for Product and Store. How can I improve the database design?

My concern is mainly for the categories be user friendly. For example Men -> Clothing -> Shirts as a category. If you wish, you can help me to improve the design as well, I would appreciate all recommendations.

I am using Python 3 and Django 1.11.

DAY = (( 'Sun', 'Sunday'),
       ( 'Mon', 'Monday'),
       ( 'Tue', 'Tuesday'),
       ( 'Wed', 'Wednesday'),
       ( 'Thu', 'Thursday'),
       ( 'Fri', 'Friday'),
       ( 'Sat', 'Saturday')
    )

class OpeningHours(models.Model):
    store = models.ForeignKey('Store', related_name="opening_hour")
    weekday = models.CharField(choices=DAY, max_length=12)
    opening_hour = models.TimeField()
    closing_hour = models.TimeField()

    class Meta:
        verbose_name = 'Opening Hour'
        verbose_name_plural = 'Opening Hours'

    def ___str__(self):
        return '{} {} - {}'.format(self.weekday, str(self.opening_hour), str(self.closing_hour))

class Store(models.Model):
    merchant = models.ForeignKey(User, blank=True, null=False)
    token = models.CharField(default=token_generator, max_length=20, unique=True, editable=False)
    name_of_legal_entity = models.CharField(max_length=250, blank=False, null=False)
    pan_number = models.CharField(max_length=20, blank=False, null=False)
    registered_office_address = models.CharField(max_length=200)
    name_of_store = models.CharField(max_length=100)
    email = models.EmailField(blank=False, null=False)
    store_contact_number = models.PositiveIntegerField(blank=False, null=False)
    # store_long = models.DecimalField(max_digits=12, decimal_places=8, null=True)
    # store_lat = models.DecimalField(max_digits=12, decimal_places=8, null=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        verbose_name = 'Store'

    def __str__(self):
        return self.name_of_store

    class Meta:
        verbose_name = 'Store'
        verbose_name_plural = 'Stores'

class Product(models.Model):
    store = models.ForeignKey(Store)
    token = models.CharField(default=token_generator, max_length=20, unique=True, editable=False)
    category = models.ForeignKey('CatalogCategory', related_name='products')
    brand = models.ForeignKey('Brand', related_name="product_brand")
    image = models.ImageField(upload_to='products/images/')
    name_of_product = models.CharField(max_length=120, blank=False,null=False)
    description = models.TextField(blank=False,null=False)
    price = models.DecimalField(decimal_places=2, max_digits=20)
    discount = models.DecimalField(decimal_places=2, max_digits=20)
    sales_price = models.DecimalField(decimal_places=2, max_digits=20)
    is_active = models.BooleanField(default=True)
    is_gurantee_available = models.BooleanField(default=False)
    is_negotiated = models.BooleanField(default=False)
    is_verified = models.BooleanField(default=False)
    is_instock = models.BooleanField(default=False)

    def __str__(self):
        return self.name_of_product

    class Meta:
        verbose_name = 'Product'
        verbose_name_plural = 'Products'


class Brand(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    logo = models.ImageField(upload_to='products/brand/images/')

    class Meta:
        verbose_name = 'Brand'
        verbose_name_plural = 'Brands'

    def __str__(self):
        return self.name

class Variation(models.Model):
    VAR_CATEGORIES = (
        ('size', 'size'),
        ('color', 'color'),
    )

    product = models.ForeignKey(Product)
    token = models.CharField(default=token_generator, max_length=20, unique=True, editable=False)
    category = models.CharField(max_length=10, choices=VAR_CATEGORIES)
    title = models.CharField(max_length=50)
    price = models.DecimalField(decimal_places=2, max_digits=20)
    discount = models.DecimalField(blank=True ,null =True, decimal_places=2, max_digits=20)
    active = models.BooleanField(default=True)
    quantity = models.IntegerField(null=True , blank=True)
    sales_price = models.DecimalField(blank=True ,null =True, decimal_places=2, max_digits=20)
    image = models.ImageField(upload_to='products/images/')

    class Meta:
        verbose_name = 'Variation'
        verbose_name_plural = 'Variations'

    def __str__(self):
        return '{0} of {1} from {2}' .format(self.product.name_of_product, self.title, self.product.store.name_of_store)


class CatalogCategory(models.Model):
    token = models.CharField(default=token_generator, max_length=20, unique=True, editable=False)
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
    name = models.CharField(max_length=300)
    description = models.TextField(blank=True)

    class Meta:
        verbose_name = 'CatalogCategory'
        verbose_name_plural = 'CatalogCategories'

    def __str__(self):
        return self.name


class ProductImage(models.Model):
    product = models.ForeignKey(Product, null=True, blank=True, related_name="product_image")
    image = models.ImageField(upload_to='products/images/')
    updated = models.DateTimeField(auto_now_add=False, auto_now=True)

    @property
    def imageName(self):
        return str(os.path.basename(self.image.name))

    def __str__(self):
        return str(self.image)

    class Meta:
        verbose_name = 'Product Image'
        verbose_name_plural = 'Product Images'


class StoreCategory(models.Model):
    STORE_CATEGORIES= (
        ('GROCERY', ('Grocery')),
        ('MEATS', ('Meats')),
        ('FOODS & BEVERAGES', ('Foods')),
        ('COMPUTERS', ('Computers')),
        ('ELECTRONICS', ('Electronics')),
        ('HOME & OUTDOOR', ('Home & Outdoor')),
        ('FASHION & BEAUTY', ('Fashion & Beauty')),
        ('HEALTH', ('Health')),
        ('SPORTS & FITNESS', ('Sports & Fitness')),
        ('BABY', ('Baby')),
        ('BOOKS', ('Books')),
    )

    product = models.ForeignKey(Product,null=True, on_delete=models.CASCADE)
    store_category = models.CharField(choices=STORE_CATEGORIES, default='GROCERY', max_length=30)
    # objects = VariationManager()

    class Meta:
        verbose_name = 'Store Category'
        verbose_name_plural = 'Store Categories'

    def __str__(self):
        # return str(self.product.name_of_product)
        return '{0} of category {1}' .format(self.product.name_of_product, str(self.store_category))
\$\endgroup\$
1
\$\begingroup\$

The models look about right.

def imageName(self):

Well, ok, PEP-8 asks that you spell this image_name, but, whatever, I'm sure you had other constraints you were working within.

In STORE_CATEGORIES I don't understand why Foods is special. It otherwise has DRY issues that could be addressed by applying .upper() or .title() to a single copy of the list.

Looks good to me. Ship it!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.