Как управлять булевыми флагами в Django?

Может ли кто-нибудь объяснить, какую лучшую практику я должен использовать для управления флагами в моих моделях Django, которые будут сериализовываться в DRF
. У меня есть такая модель:

class Project(models.Model):
* Логика *
is_free = models.BooleanField(default = True)

 is_paid = models.BooleanField(default = False)

 is_free_or_donate = models.BooleanField(default = False)

Как мне управлять этими флагами в Django?

Должен ли я использовать для этого методы модели, чтобы инкапсулировать логику внутри модели? Или, может быть, переписать методы сохранения и сделать это там? Буду благодарен за советы о лучших практиках

Как я могу изменить флаги в зависимости от других флагов в моей модели. Например, клиент выбирает is_paid для проекта. но флаг is_free остается True.

Обычно стараются сделать поля ортонормальными, другими словами, свободно изменяющимися друг от друга. Поля, которые (полностью) зависят от других полей, определяются как свойства или вычисляемые поля.

Так что здесь можно было бы использовать:

class Project(models.Model):
    is_paid = models.BooleanField(default=False)

    @property
    def is_free(self):
        return not self.is_paid

Создание двух полей, которые (полностью) зависят друг от друга, создаст множество проблем: вам нужно продумать все возможные сценарии изменения одного из двух полей и то, как это повлияет на другое(-ие). Это также означает, что вы используете больше памяти, и если другая программа вносит изменения в базу данных, все может пойти не так.

Если поля в какой-то степени зависят друг от друга, это обычно означает, что существует более фундаментальное поле. Например, у вас может быть voucher, которое перестает действовать, если истекает срок действия due_date или если кто-то активно отключает его.

Тогда вместо использования:

# wrong
class Voucher(models.Model):
    due_date = models.DateField()
    expired = models.BooleanField()

вы используете:

# right

from datetime import date


class Voucher(models.Model):
    due_date = models.DateField()
    invalidated = models.BooleanField(default=False)

    @property
    def expired(self):
        self.due_date < date.today() and not self.invalidated

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

  1. Избегайте избыточных булевых полей:

Использование нескольких булевых полей, которые являются взаимоисключающими (например, is_free, is_paid, is_free_or_donate), может привести к ошибкам и усложнить сопровождение кода. Вместо того чтобы использовать несколько булевых полей, подумайте об использовании одного поля CharField или IntegerField с вариантами выбора для представления состояния вашей модели проекта.

  1. Использование вариантов с одним полем:

Замените несколько булевых полей одним полем, в котором используется выбор. Это позволит понять, что проект может находиться только в одном состоянии одновременно.

class Project(models.Model):
    FREE = 'free'
    PAID = 'paid'
    FREE_OR_DONATE = 'free_or_donate'

    PROJECT_TYPES = [
        (FREE, 'Free'),
        (PAID, 'Paid'),
        (FREE_OR_DONATE, 'Free or Donate'),
    ]

    project_type = models.CharField(
        max_length=20,
        choices=PROJECT_TYPES,
        default=FREE,
        verbose_name="Project Type"
    )

Такой подход избавляет от необходимости управлять несколькими булевыми полями и гарантирует, что тип проекта является взаимоисключающим.

  1. Сериализация с помощью Django Rest Framework (DRF):

При использовании DRF поле choices автоматически сериализуется как строка, что может быть легко обработано в ваших сериализаторах.

from rest_framework import serializers

class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = '__all__'
  1. Заключение:

Лучшей практикой в этом случае является замена нескольких булевых полей одним CharField или IntegerField с помощью choices, что обеспечивает взаимоисключаемость и упрощает логику модели. Кроме того, инкапсулируйте связанную логику в методах модели для обеспечения чистоты и удобства обслуживания кодовой базы.

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