Проектирование моделей в Django

В этой статье хотелось бы поделиться опытом и помочь в проектировании и оформлении вашего кода на Django. Надеюсь, что вы уже используете PEP8, но также является хорошим тоном использовать рекомендации по стилям форматирования кода от Django.

Ниже можно ознакомиться с рекомендациями по оформлению кода на Django.

Названия моделей

Так как модель — это класс, то всегда используем соглашение CapWords, т. е. каждое слово в имени модели начинаем с заглавной буквы, без подчеркиваний. Например User, Permission, ContentType и т. д.

Для атрибутов моделей используем snake_case, т.е. все слова с маленькой буквы с разделением подчеркиванием. Например first_name, last_name.

Пример:

from django.db import models

class Company(models.Model):
    name = models.CharField(max_length=30)
    vat_identification_number = models.CharField(max_length=20)

Также для имени модели всегда используйте единственное число: Company вместо Companies. Определение модели — это представление единственного объекта (в данном примере компания), а не множества.

С непривычки это вызывает некоторое недоразумение, если вы привыкли мыслить в понятиях таблиц базы данных. В конечном итоге модель будет переведена в таблицу. Для названия таблицы вполне правильно использовать множественное число, так как таблица представляет собой совокупность объектов.

Последовательность размещения внутри класса модели

Рекомендации Django по последовательности размещения внутренних классов, методов и атрибутов следующие:

  • если для поля модели определены варианты (choices), определите каждый вариант выбора как кортеж кортежей, используя заглавные буквы;
  • поля данных модели;
  • атрибуты пользовательского менеджера;
  • class Meta;
  • def __str__();
  • def save();
  • def get_absolute_url();
  • остальные методы вашего класса.

Пример:

from django.db import models
from django.urls import reverse

class Company(models.Model):
    # CHOICES
    PUBLIC_LIMITED_COMPANY = 'PLC'
    PRIVATE_COMPANY_LIMITED = 'LTD'
    LIMITED_LIABILITY_PARTNERSHIP = 'LLP'
    COMPANY_TYPE_CHOICES = (
        (PUBLIC_LIMITED_COMPANY, 'Public limited company'),
        (PRIVATE_COMPANY_LIMITED, 'Private company limited by shares'),
        (LIMITED_LIABILITY_PARTNERSHIP, 'Limited liability partnership'),
    )

    # DATABASE FIELDS
    name = models.CharField('name', max_length=30)
    vat_identification_number = models.CharField('VAT', max_length=20)
    company_type = models.CharField('type', max_length=3, choices=COMPANY_TYPE_CHOICES)

    # MANAGERS
    objects = models.Manager()
    limited_companies = LimitedCompanyManager()

    # META CLASS
    class Meta:
        verbose_name = 'company'
        verbose_name_plural = 'companies'

    # TO STRING METHOD
    def __str__(self):
        return self.name

    # SAVE METHOD
    def save(self, *args, **kwargs):
        do_something()
        super().save(*args, **kwargs)  # Call the "real" save() method.
        do_something_else()

    # ABSOLUTE URL METHOD
    def get_absolute_url(self):
        return reverse('company_details', kwargs={'pk': self.id})

    # OTHER METHODS
    def process_invoices(self):
        do_something()

Обратные отношения

related_name

Это атрибут используется в поле ForeignKey. Он позволяет указать нормальное и удобное имя для обратного отношения (reverse relationship).

Например:

class Company:
    name = models.CharField(max_length=30)

class Employee:
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='employees')

Этот код означает, что у объекта модели Company появится атрибут employees, который возвращает QuerySet со всеми объектами работников указанной компании.

google = Company.objects.get(name='Google')
google.employees.all()

Пустые и нулевые поля

Разница между пустыми и нулевыми полями уже обсуждалась, но повторю:

  • null: связан с базой данных, определяет, будет ли данный столбец базы данных принимать нулевые значения или нет.
  • blank: связан с валидацией Django, используется во время проверки формы при вызове form.is_valid ().

Не используйте значение null=True для текстовых полей, которые являются необязательными. В противном случае вы получите два возможных значения для «нет данных»: «Нет» и пустая строка. Наличие двух возможных значений для «нет данных» является избыточным. Соглашение Django должно использовать пустую строку, а не NULL.

# The default values of `null` and `blank` are `False`.
# значение по умолчанию для null и blank - False
class Person(models.Model):
    name = models.CharField(max_length=255)  # обязательное
    bio = models.TextField(max_length=500, blank=True) # необязательное (не используйте null=True для текстовых полей)
    birth_date = models.DateField(null=True, blank=True) # необязательное (здесь нужно использовать оба атрибута null и blank)

Заключение

Определение модели — важная часть вашего приложения. Детальное рассмотрение рекомендаций вы можете посмотреть в документации Django’s Coding Style.

Вернуться на верх