5.17. Models Directory

  • Fat model architecture

  • Single File vs. Models per file

  • Important, add app_label to model's Meta class

  • Important, add __init__.py to the shop/models/ directory

  • Important, import from .customer import * in shop/models/__init__.py

5.17.1. Files and Directory Structure

shop/
├── models/
│   ├── __init__.py
│   ├── customer.py
│   ├── address.py
│   ├── order.py
│   ├── product.py
├── admin.py
├── apps.py
├── tests.py
├── views.py

5.17.2. Models

  • One model per file

  • Important, add app_label to model's Meta class

  • Use string in ForeignKey to avoid circular import

  • Supporting classes like choices, relations and helper functions, etc. can be in the same file

File: shop/models/customer.py

>>> 
... from django.db import models
... from django.utils.translation import gettext_lazy as _
...
...
... class Customer(models.Model):
...     firstname = models.CharField(verbose_name=_('First Name'), max_length=50)
...     lastname = models.CharField(verbose_name=_('Last Name'), max_length=50, db_index=True)
...     email = models.EmailField(verbose_name=_('Email'), max_length=100, null=True, blank=True, default=None, unique=True)
...
...     def __str__(self):
...         return f'{self.firstname} {self.lastname}'
...
...     class Meta:
...         app_label = 'shop'
...         verbose_name = _('Customer')
...         verbose_name_plural = _('Customers')

File: shop/models/address.py

>>> 
... from django.db import models
... from django.utils.translation import gettext_lazy as _
...
...
... class AddressType(models.TextChoices):
...     HOME = 'home', _('Home')
...     WORK = 'work', _('Work')
...     BILLING = 'billing', _('Billing')
...     SHIPPING = 'shipping', _('Shipping')
...
...
... class Address(models.Model):
...     customer = models.ForeignKey(verbose_name=_('Customer'), to='shop.Customer', on_delete=models.CASCADE, related_name='address')
...     type = models.CharField(verbose_name=_('Type'), choices=AddressType, max_length=20, null=False, blank=False)
...     street = models.CharField(verbose_name=_('Street'), max_length=100, null=False, blank=False)
...     house = models.CharField(verbose_name=_('House Number'), max_length=20, null=False, blank=False)
...     apartment = models.CharField(verbose_name=_('Apartment Number'), max_length=20, null=True, blank=True, default=None)
...     postcode = models.CharField(verbose_name=_('Post Code'), max_length=20, null=False, blank=False)
...     city = models.CharField(verbose_name=_('City'), max_length=100, null=False, blank=False)
...     region = models.CharField(verbose_name=_('Region'), max_length=100, null=True, blank=True, default=None)
...     country = models.CharField(verbose_name=_('Country'), max_length=100, null=False, blank=False)
...
...     class Meta:
...         app_label = 'shop'
...         verbose_name = _('Address')
...         verbose_name_plural = _('Addresses')
...
...     def __str__(self):
...         return f'{self.street} {self.house}, {self.city}'

5.17.3. Init File

  • Important, add __init__.py to the shop/models/ directory

  • Important, import from .customer import * in shop/models/__init__.py

File: shop/models/__init__.py:

from .customer import *
from .address import *
from .order import *
from .product import *