Search code examples
djangodatabasemodel

Django model relations and dividing models into few tables in larger project


I have few problems with Django models (relations mostly), but I'll start from code than make desciption and put questions...

Django models and relations in short (very simplified) version:

# Shorten version of services
SERVICES = [
 ("TC", "Tires Cleaning"),
 ("EC", "Exterior Cleaning"),
 ("IC", "Interior Cleaning"),
 ("CW", "Cleaning & Washing - full service"),
 ("WX", "Application of wax"),
]


class Client(models.Model):
    name = models.CharField(max_length=35)
    surname = models.CharField(max_length=35)
    car = models.CharField(max_length=25)


class SingleService(models.Model):
    service_name = models.CharField(max_length=35)    
    service_type = models.CharField(max_length=1, choices=SERVICES, default="CW")
    price = models.IntegerField()


class SetOfServices(models.Model):
    set_of_services = ????
    price_of_set = ???


class Purchase(models.Model):
    client = OneToOneField(client)  
    order = models.ForeignKey(SetOfServices, on_delete=models.CASCADE, blank=True, null=True)
    price = ???

I want to make small project (Car Wash) with 8+ django models. Client is coming to car wash and I want to store its name/ surname and car make/model/type etc in DB for future refference (clients coming back will get discount and free coffee). Then I have SingleService model with about 20-30 services - they have different name and price because of diferernt tasks / time to make and options / extra features. SetOfServices model must consist of few single services (custom, but customized from Django admin panel, probably only once, at setup / configuration time). So it must be set of few services (I don't want client to buy only one / single service!), like:

Example SET 1: Tires cleaning + Interior cleaning

Example SET 2: Exterior cleaning + Application of wax

....and so on. I want to join few services in one set of services client can buy (with some discount - for example).

The last model (from above code, I plan to expand this project) is Purchase where Client orders one SetOfServices and pay some money. The problems I encountered is choosing right relation for set_of_services field and how to calculate overall price of this set (price_of_set field). Should I use ForeignKey (One to Many) relation in set_of_service field?

How to divide Django models (when project expands) into few tables in database (I am using PostgreSQL)? Could you give me refference or example code for it? I know we use db_table in Meta description of models, but how the relations change??


Solution

  • The question you want to ask yourself is:

    • Does one SetOfServices contain multiple SingleServices --> YES
    • Does one SingleService show up in multiple different SetOfServices? --> YES

    If your result to these questions is two times YES the relationship is a many-to-many.

    class SetOfServices(models.Model):
        set_of_services = models.ManyToManyField(SingleService)
        # price_of_set --> does this really need to be stored in database?
       
        @property
        def price_of_set(self):
            return sum([service.price for service in self.set_of_services.all()])
    

    Now you want to ask yourself:

    • Does a Purchase allow buying multiple SetOfServices (this is dependent on your choice)? --> NO
    • Is a SetOfServices bought by multiple Purchases? --> YES

    YES YES --> ManyToMany
    NO YES --> OneToMany --> ForeignKey

    class Purchase(models.Model):
        client = OneToOneField(client)  
        order = models.ForeignKey(SetOfServices, on_delete=models.CASCADE, blank=True, null=True)
        # same advice as above for price = ???
    
        @property
        def price(self):
            return self.order.price_of_set
    

    To be honest I feel like your setup of models is already kinda stable. I can't tell you how to divide models at runtime of a project. I've never done it.

    Let me know how it goes!

    Edit after comment of OP

    Depending on your "staring point" you can access the price inside of your templates. Here some examples:

    <h1>Object = Purchase</h1>
    {{ object.price }}
    <h1>Object = SetOfServices</h1>
    {{ object.price_of_set }}
    <h1>Object = SingleService</h1>
    {{ object.price }}