10 трюків з моделями Django, які часто ігнорують розробники

Django ORM є потужним інструментом, але навіть досвідчені розробники можуть не використовувати його на повну силу. У цьому пості я поділюсь деякими маловідомими порадами та трюками для створення класів моделей Django, які допоможуть спростити ваш код, покращити продуктивність і зробити вашу роботу як розробника легшою.

1. Використовуйте опції Meta для магії

Клас Meta в моделях Django — це не просто місце для визначення verbose назв. Він має численні можливості, які можуть значно зменшити кількість шаблонного коду. Ось кілька важливих моментів:

A. За замовчуванням сортування

Замість того, щоб вручну сортувати querysets у кожному вигляді, визначте сортування за замовчуванням у вашій моделі:

from django.db import models  

class Product(models.Model):  
    name = models.CharField(max_length=255)  
    price = models.DecimalField(max_digits=10, decimal_places=2)  

    class Meta:  
        ordering = ['-price'] # Продукти будуть відсортовані за ціною у спадаючому порядку

B. Кастомні імена таблиць

Якщо вам потрібно дотримуватись специфічних конвенцій бази даних, ви можете змінити ім'я таблиці прямо в моделі:

from django.db import models  

class Product(models.Model):  
    name = models.CharField(max_length=255)  

    class Meta:  
        db_table = 'custom_product_table'

2. Використовуйте __str__() ефективно

Це поширена практика — визначити метод __str__() для моделі, але чому б не зробити більше, ніж просто вивести ім'я? Ви можете зробити відлагодження та ведення логів простішими, включивши додатковий контекст:

from django.db import models  

class Order(models.Model):  
    order_id = models.CharField(max_length=100)  
    customer_name = models.CharField(max_length=255)  

    def __str__(self):  
        return f"Order {self.order_id} by {self.customer_name}"

Таким чином, ваші об'єкти надаватимуть змістовні представлення під час розробки та тестування.

3. Абстрактні базові моделі для спільних полів

Замість того, щоб повторювати загальні поля, такі як created_at та updated_at у кожній моделі, створіть абстрактну базову модель:

from django.db import models  

class TimestampedModel(models.Model):  
    created_at = models.DateTimeField(auto_now_add=True)  
    updated_at = models.DateTimeField(auto_now=True)  

    class Meta:  
        abstract = True  

class Product(TimestampedModel):  
    name = models.CharField(max_length=255)

Тепер кожна модель, що наслідує TimestampedModel, автоматично матиме поля created_at та updated_at.

4. Використовуйте choices для значень полів

Для полів з обмеженими варіантами, використовуйте можливість choices в Django для кращої читабельності коду та узгодженості з базою даних:

from django.db import models  

class Product(models.Model):  
    STATUS_CHOICES = [  
        ('active', 'Active'),  
        ('inactive', 'Inactive'),  
        ('out_of_stock', 'Out of Stock'),  
    ]  

    name = models.CharField(max_length=255)  
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')

Бонус: Використовуйте перерахування Django 3.0+ для ще чистішого коду:

from django.db import models  

class ProductStatus(models.TextChoices):  
    ACTIVE = 'active', 'Active'  
    INACTIVE = 'inactive', 'Inactive'  
    OUT_OF_STOCK = 'out_of_stock', 'Out of Stock'  

class Product(models.Model):  
    name = models.CharField(max_length=255)  
    status = models.CharField(max_length=20, choices=ProductStatus.choices, default=ProductStatus.ACTIVE)

5. Ефективні пошуки по полях з індексуванням

Django дозволяє визначати індекси бази даних на рівні поля або через клас Meta. Використовуйте їх для оптимізації продуктивності запитів:

from django.db import models  

class Product(models.Model):  
    name = models.CharField(max_length=255)  
    sku = models.CharField(max_length=50, unique=True) # код товару  

    class Meta:  
        indexes = [  
            models.Index(fields=['sku']), # Додає індекс до поля SKU  
        ]

## Динамічні значення полів з `callable`

Поля Django можуть приймати динамічні значення за допомогою `callable` (функції або об'єкти, які можна викликати), що дозволяє ініціалізувати поля динамічно:

from django.db import models
import uuid

class Order(models.Model):
orderid = models.UUIDField(default=uuid.uuid4, editable=False)
created
at = models.DateTimeField(autonowadd=True)
```

У цьому випадку кожен екземпляр Order отримає унікальний order_id без необхідності вручну встановлювати його.

7. Сигнали чудові, але менеджери моделей краще для логіки

Замість того, щоб покладатися на сигнали для загальної логіки до збереження чи після збереження, використовуйте власні менеджери моделей. Вони простіші для підтримки та тестування:

class ProductManager(models.Manager):  
    def active(self):  
        return self.filter(status='active')  

class Product(models.Model):  
    name = models.CharField(max_length=255)  
    status = models.CharField(max_length=20, choices=[('active', 'Active'), ('inactive', 'Inactive')])  

    objects = ProductManager()

Тепер ви можете фільтрувати активні продукти так:

Product.objects.active()

8. Додавайте обмеження для цілісності даних

Django 3.2 введено CheckConstraint, що дозволяє застосовувати правила на рівні бази даних:

from django.db.models import Q, CheckConstraint  

class Product(models.Model):  
    name = models.CharField(max_length=255)  
    price = models.DecimalField(max_digits=10, decimal_places=2)  

    class Meta:  
        constraints = [  
            CheckConstraint(check=Q(price__gte=0), name='price_positive')  
        ]

Це гарантує, що поле price завжди буде невід'ємним.

9. Кастомні QuerySet для повторного використання

Якщо ви часто фільтруєте моделі однаковим чином, використовуйте кастомні QuerySet (запити до бази даних) для більш чистого та повторно використовуваного коду:

class ProductQuerySet(models.QuerySet):  
    def expensive(self):  
        return self.filter(price__gte=1000)  

class Product(models.Model):  
    name = models.CharField(max_length=255)  
    price = models.DecimalField(max_digits=10, decimal_places=2)
objects = ProductQuerySet.as_manager()

Тепер ви можете запитувати дорогі продукти так:

expensive_products = Product.objects.expensive()

10. Використовуйте можливості бази даних за допомогою сирого SQL

Для складних запитів не бійтеся використовувати сирий SQL. ORM Django дозволяє поєднувати обидва варіанти без проблем:

from django.db import models  

class Product(models.Model):  
    name = models.CharField(max_length=255)  

    @classmethod  
    def top_selling(cls):  
        return cls.objects.raw('SELECT * FROM product ORDER BY sales DESC LIMIT 10')

Висновок

Моделі Django — це більше, ніж просто спосіб відображати класи Python на таблиці бази даних. Використовуючи ці поради та трюки, ви можете писати більш чистий, ефективний код, одночасно оптимізуючи продуктивність і підтримуваність.

Незалежно від того, чи ви новачок, чи досвідчений розробник Django, ці трюки допоможуть вам вивести ваші навички на новий рівень. Який з цих трюків здивував вас найбільше? Поділіться своїми думками в коментарях!

Перекладено з: 10 Django Model Tricks Developers Often Overlook

Leave a Reply

Your email address will not be published. Required fields are marked *