Пример #1
0
class Progress(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion

    user = _related.ForeignKey(
        'entry.User',
        on_delete=_deletion.CASCADE,
        verbose_name="Пользователь",
        null=False,
        blank=False,
    )

    feature = _related.ForeignKey(
        'entry.Feature',
        on_delete=_deletion.CASCADE,
        verbose_name="Фича",
        null=False,
        blank=False,
    )

    def __str__(self):
        return "Прогресс по %s для пользователя %s" % (self.feature, self.user)

    class Meta:
        verbose_name = 'Прогресс'
        verbose_name_plural = 'Прогресс'
Пример #2
0
class PaymentDetails(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field
    from datetime import datetime as _dt

    company = _related.ForeignKey(
        'holding.Company',
        on_delete=_deletion.CASCADE,
        null=False,
        blank=False,
    )

    rate = _related.ForeignKey(
        'pay.Rate',
        on_delete=_deletion.CASCADE,
        verbose_name="Выбранный тариф",
        null=False,
        blank=False,
    )

    discount = _related.ForeignKey(
        'pay.Discount',
        on_delete=_deletion.CASCADE,
        null=True,
        blank=False,
    )

    start = _field.DateTimeField(
        "Дата начала действия тарифа",
        default=_dt.now,
    )

    discount_percent = _field.PositiveSmallIntegerField(
        "Процент скидки на момент платежа",
        default=None,
        null=True,
        blank=True,
    )

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        if not self.discount:
            self.discount = self.company.discount

        if self.discount:
            self.discount_percent = self.discount.percent

        super().save(force_insert=force_insert,
                     force_update=force_update,
                     using=using,
                     update_fields=update_fields)

    class Meta:
        verbose_name = "Дополнительные детали"
        verbose_name_plural = "Детали оплат"
class FieldValue(models.Model):
    answer = related.ForeignKey(QuestionnaireAnswer, on_delete=models.CASCADE,
                                related_name='field_values')
    field = related.ForeignKey(QuestionnaireField, on_delete=models.CASCADE)
    value = fields.CharField(max_length=255)

    class Meta:
        unique_together = ('answer', 'field')
Пример #4
0
class Face(_Model):
    from django.contrib.contenttypes.fields import GenericRelation as _Generic
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field

    employee = _related.ForeignKey(
        'holding.Employee',
        on_delete=_deletion.CASCADE,
        null=False,
        blank=False,
    )

    face_id = _field.CharField(
        verbose_name="Face ID",
        max_length=64,
    )

    photo = _Generic(
        'common.Image',
        verbose_name="Фотография",
        null=True,
    )

    class Meta:
        verbose_name = "Лицо"
        verbose_name_plural = "Лица"
Пример #5
0
class Teacher(models.Model):
    name = models.CharField(max_length=200)
    first_name = models.CharField(max_length=200)
    user = related.ForeignKey(CustomUser, on_delete=models.CASCADE)

    def __str__(self):
        return self.name
Пример #6
0
class Video(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field

    start = _field.DateTimeField("Начало")
    duration = _field.DurationField("Продолжительность")

    filename = _field.CharField(
        verbose_name="Название файла",
        max_length=128,
        null=False,
        blank=False,
    )

    # There is need to be link to file

    camera = _related.ForeignKey(
        'cam.Camera',
        on_delete=_deletion.CASCADE,
        null=False,
        blank=False,
    )

    @property
    def timezone(self):
        return self.camera.timezone if self.camera.timezone else self.camera.company.timezone

    class Meta:
        verbose_name = "Видео"
        verbose_name_plural = "Видео"
Пример #7
0
class PositionToDepartment(_Model):
    position = _related.ForeignKey(
        Position,
        on_delete=_deletion.CASCADE,
        null=False,
        blank=False,
        related_name="departments",
    )

    department = _related.ForeignKey(
        'holding.Department',
        on_delete=_deletion.CASCADE,
        null=False,
        blank=False,
        related_name="positions",
    )

    def __str__(self):
        return "Должность %s из отдела %s (%s)" % (self.position, self.department, self.position.company)

    class Meta:
        verbose_name = "Должность к отделу"
        verbose_name_plural = "Должности к отделам"
Пример #8
0
class Violation(_Model):
    employee = _related.ForeignKey(
        'holding.Employee',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=False,  # For admin panel?
        related_name="violations",
    )

    when = _field.DateTimeField("Когда")

    title = _field.CharField(
        verbose_name="Название нарушения",
        null=False,
        blank=False,
        max_length=128,
    )

    description = _field.TextField(
        verbose_name="Описание нарушения",
        null=True,
        blank=True,
    )

    timezone = _timezone.TimeZoneField(
        verbose_name="Временная зона",
        null=True,
        blank=True,
    )

    @property
    def employee_fullname(self):
        return "%s %s" % (self.employee.first_name, self.employee.last_name)

    employee_fullname.fget.short_description = "Сотрудник"

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        if self.timezone is None:
            self.timezone = self.employee.company.timezone

        return super(Violation, self).save(force_insert, force_update, using, update_fields)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "Нарушение"
        verbose_name_plural = "Нарушения"
Пример #9
0
class Position(_Model):
    name = _field.CharField(
        verbose_name="Название должности",
        max_length=255,
        null=False,
        blank=False,
    )

    company = _related.ForeignKey(
        'holding.Company',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=True,
        related_name="positions",
    )

    is_protected = _field.BooleanField(
        verbose_name='Неудаляемая должность',
        default=False,
    )

    @property
    def department_id(self):
        department = self.departments.first()

        if department:
            return department.id
        return department

    def __str__(self):
        return self.name

    def delete(self, **kwargs):
        if self.is_protected:
            raise _APIException({
                'detail': 'Protected',
                'protected': True,
            }, status_code=403)

        super(Position, self).delete(**kwargs)

    class Meta:
        verbose_name = "Должность"
        verbose_name_plural = "Должности"
class QuestionnaireField(models.Model):
    FIELD_TYPES = (
        ('TXT', 'text'),
        ('RAD', 'radiobutton'),
        ('CHK', 'checkbox'),
        ('NUM', 'number_choice')
    )
    questionnaire = related.ForeignKey(Questionnaire, on_delete=models.CASCADE,
                                       related_name='fields')
    position = fields.IntegerField()
    field_type = fields.CharField(max_length=3, choices=FIELD_TYPES)
    text_before = fields.CharField(max_length=255)
    text_after = fields.CharField(max_length=255, blank=True)
    default_val = fields.CharField(max_length=255, blank=True)
    min_val = fields.IntegerField(null=True)
    max_val = fields.IntegerField(null=True)

    class Meta:
        unique_together = ('questionnaire', 'position')
        ordering = ['position']
Пример #11
0
class Zone(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field

    company = _related.ForeignKey(
        'holding.Company',
        on_delete=_deletion.CASCADE,
        related_name="zones",
    )

    name = _field.CharField(
        verbose_name="Название",
        max_length=128,
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "Зона"
        verbose_name_plural = "Зоны"
Пример #12
0
class Image(_Model):
    from django.contrib.contenttypes.fields import GenericForeignKey as _GenericForeign
    from django.contrib.contenttypes.models import ContentType as _Type
    from django.db.models.fields.files import ImageField as _image
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field

    content_type = _related.ForeignKey(_Type,
                                       on_delete=_deletion.CASCADE,
                                       verbose_name="Модель")
    object_id = _field.PositiveIntegerField(verbose_name="Ключ")
    content_object = _GenericForeign()

    def computed_folder(self, file_name):
        import uuid
        from app.base.helpers import snake
        extension = file_name.split('.')[-1]

        return "%s/%d/%s" % (snake(self.content_type.model_class().__name__),
                             self.object_id, "%s.%s" %
                             (uuid.uuid4(), extension))

    image = _image("Изображение", null=True, upload_to=computed_folder)

    # Can be empty...
    description = _field.CharField(verbose_name="Описание",
                                   null=True,
                                   blank=True,
                                   max_length=512)

    def __str__(self):
        return "Изображение для %s [№ %d]" % (self.content_type,
                                              self.object_id)

    class Meta:
        verbose_name = "Изображение"
        verbose_name_plural = "Изображения"
Пример #13
0
class CompanyCreator(_Model):
    creator = _related.OneToOneField(
        to='holding.Employee',
        on_delete=_deletion.DO_NOTHING,
        verbose_name='Создатель',
        related_name='creators',
    )

    company = _related.OneToOneField(
        to='holding.Company',
        on_delete=_deletion.CASCADE,
        verbose_name='Компания',
        related_name='companies',
    )

    physical = _related.ForeignKey(
        to='entry.User',
        on_delete=_deletion.DO_NOTHING,
        verbose_name='Физический пользователь',
        related_name='users',
        blank=True,
        null=True,
    )

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        self.physical = self.creator.user

        super(CompanyCreator, self).save(force_insert, force_update, using,
                                         update_fields)

    class Meta:
        verbose_name = 'Основатель'
        verbose_name_plural = 'Основатели'
class QuestionnaireAnswer(models.Model):
    questionnaire = related.ForeignKey(Questionnaire, on_delete=models.CASCADE)
    respondent = related.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        unique_together = ('questionnaire', 'respondent')
Пример #15
0
class Schedule(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field
    from app.fields import timezone as _timezone

    employee = _related.ForeignKey(
        'holding.Employee',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=False,  # For admin panel?
        related_name="schedules",
    )

    start = _field.DateTimeField("Начало")
    end = _field.DateTimeField("Конец")

    is_wanted = _field.NullBooleanField(
        verbose_name="Хочет работать",
        default=None,
    )

    timezone = _timezone.TimeZoneField(
        verbose_name="Временная зона",
        null=True,
        blank=True,
    )

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        if self.timezone is None:
            self.timezone = self.company.timezone

        return super(Schedule, self).save(force_insert, force_update, using,
                                          update_fields)

    @property
    def employee_fullname(self):
        return "%s %s" % (self.employee.first_name, self.employee.last_name)

    employee_fullname.fget.short_description = "Сотрудник"

    @property
    def company(self):
        return self.employee.company

    company.fget.short_description = "Компания"

    @property
    def company_name(self):
        return self.company.name

    company_name.fget.short_description = "Компания"

    def __str__(self):
        return "%s %s [%s]:(%s - %s)" % (
            self.employee.first_name, self.employee.last_name,
            self.start.date(), self.start.time(), self.end.time())

    class Meta:
        verbose_name = "График сотрудника"
        verbose_name_plural = "Графики сотрудников"
Пример #16
0
class Company(_Model):
    from app.fields import timezone as _timezone

    name = _field.CharField(
        verbose_name='Название компании',
        max_length=255,
        null=False,
    )

    description = _field.TextField(
        verbose_name='Описание компании',
        max_length=4000,
        null=True,
        blank=True,
    )

    address = _field.CharField(
        verbose_name='Адрес компании',
        max_length=512,
        null=True,
        blank=True,
    )

    phone = _field.CharField(
        verbose_name='Телефон',
        max_length=32,
        null=True,
        blank=True,
    )

    email = _field.EmailField(
        verbose_name='Почтовый ящик',
        max_length=255,
        null=False,
    )

    owner = _related.ForeignKey(
        'holding.Employee',  # Changed company owner from user to employee because of the system flow
        verbose_name='Владелец',
        on_delete=_deletion.DO_NOTHING,
        null=False,
        related_name='owner',
    )

    discount = _related.ForeignKey(
        to='pay.Discount',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=True,
    )

    timezone = _timezone.TimeZoneField(
        verbose_name='Локальное время компании',
        default='UTC',
        null=False,
        blank=True,
    )

    def __str__(self):
        return self.name

    @property
    def last_payment(self):
        from pay.models import Payment

        return Payment.objects.filter(details__company=self).last()

    @property
    def rate(self):
        return self.last_payment.details.rate if self.last_payment else None

    rate.fget.short_description = u'Тариф'

    @property
    def time_left(self):
        return self.last_payment.time_left if self.last_payment else -1

    time_left.fget.short_description = u"Оплаченное время"

    @property
    def employee_amount(self):
        return self.employees.count()

    employee_amount.fget.short_description = u"Сотрудников"

    @property
    def departments_amount(self):
        return self.departments.count()

    departments_amount.fget.short_description = u"Отделов"

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        creation = True

        if self.id:
            creation = False

        super(Company, self).save(force_insert, force_update, using,
                                  update_fields)

        self.owner.company = self
        self.owner.save()

        if creation:
            CompanyCreator(creator=self.owner, company=self).save()

    class Meta:
        verbose_name = "Компания"
        verbose_name_plural = "Компании"
class Questionnaire(models.Model):
    author = related.ForeignKey(User, on_delete=models.CASCADE)
    description = fields.TextField(max_length=1024)
    created_at = fields.DateTimeField(auto_now_add=True)
Пример #18
0
class Employee(_Model):
    from django.db.models import fields as _field
    from app.fields import timezone as _timezone
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion

    first_name = _field.CharField(
        max_length=200,
        verbose_name="Имя",
    )

    last_name = _field.CharField(
        max_length=200,
        verbose_name="Фамилия",
    )

    phone = _field.CharField(
        max_length=200,
        verbose_name="Телефон",
        null=True,
        blank=True,
    )

    company = _related.ForeignKey(
        'holding.Company',
        on_delete=_deletion.SET_NULL,
        verbose_name="Компания",
        null=True,
        blank=True,
        related_name="employees",
    )

    is_manager = _field.BooleanField(
        verbose_name="Менеджер",
        default=False,
    )

    is_fired = _field.BooleanField(
        verbose_name="Уволен",
        default=False,
    )

    import uuid as _uuid
    auth_key = _field.UUIDField(
        verbose_name="Уникальный авторизационный ключ",
        editable=False,
        unique=True,
        null=True,
        blank=False,
        default=_uuid.uuid4,
    )

    email = _field.EmailField(
        verbose_name="E-mail",
        null=True,
        blank=True,
    )

    timezone = _timezone.TimeZoneField(
        verbose_name="Пояс",
        default="UTC",
        null=False,
        blank=True,
    )

    invitation = _field.DateTimeField(
        verbose_name="Последнее приглашение",
        null=True,
        blank=True,
    )

    is_invited = _field.BooleanField(
        verbose_name="Приглашён",
        null=False,
        default=False,
    )

    is_active = _field.BooleanField(
        verbose_name="Активен",
        null=False,
        default=False,
    )

    face_id = _field.UUIDField(
        verbose_name="Face ID",
        null=True,
        blank=True,
    )

    user = _related.ForeignKey(
        'entry.User',
        on_delete=_deletion.CASCADE,
        verbose_name="Физический пользователь",
        null=True,
        blank=True,
    )

    department = _related.ForeignKey(
        'holding.Department',
        on_delete=_deletion.SET_NULL,
        default=None,
        null=True,
        blank=True,
        related_name="employees",
    )

    position = _related.ForeignKey(
        'holding.Position',
        on_delete=_deletion.SET_NULL,
        default=None,
        null=True,
        blank=True,
        related_name="employees",
    )

    def clear_face_id(self):
        self.face_id = None

    def new_face_id(self):
        self.face_id = self._uuid.uuid4()

    def new_invitation(self):
        from datetime import datetime

        old = self.invitation
        self.invitation = datetime.now()
        return old

    def activate(self):
        self.is_invited = True
        self.is_active = True
        self.auth_key = None

    def __str__(self):
        user = self.user
        ttl = {}

        if self.last_name and self.first_name:
            ttl['first_name'] = self.first_name
            ttl['last_name'] = self.last_name
        elif user:
            if user.last_name and user.first_name:
                ttl['first_name'] = user.first_name
                ttl['last_name'] = user.last_name
            ttl['username'] = user.username

        if ttl.get('first_name'):
            if ttl.get('username'):
                return "%(first_name)s %(last_name)s [%(username)s]" % ttl
            else:
                return "%(first_name)s %(last_name)s" % ttl
        elif ttl.get('username'):
            return "%(username)s" % ttl
        else:
            return "Employee №[%d]" % self.id

    @classmethod
    def create_from_user(cls, user, **kwargs):
        """
        :type user: entry.models.User
        """
        from factory.faker import faker

        fake = faker.Faker(locale='ru_RU')

        employee = cls(
            user=user,

            first_name=user.first_name if user.first_name else fake.first_name(),
            last_name=user.last_name if user.last_name else fake.last_name(),
            timezone=user.timezone,
            phone=user.phone,
            email=user.email,
            is_active=True,
            **kwargs
        )

        employee.save()

        return employee

    def set_position(self, position, department=None):
        self.position = position

        if not department and not self.department:
            related = position.departments.first()

            if related:
                self.department = related.department
        elif department:
            self.department = department

    class Meta:
        verbose_name = "Сотрудник"
        verbose_name_plural = "Сотрудники"
        unique_together = (('user', 'company'),)

    def create_user(self, username=None):
        """
        Creates user from employee, save it and send email if application not in debug mode
        :type username: str
        """
        from django.conf import settings
        from entry.models import User

        if not self.auth_key and not username:
            raise AttributeError('No username provided or can\'t be get from auth')

        user = User(
            username=username if username else self.auth_key,
            first_name=self.first_name,
            last_name=self.last_name,
            email=self.email,
            phone=self.phone,
            timezone=self.timezone,
        )

        user.save()
        self.user = user

        if user.email and not settings.DEBUG:
            user.mail_activation()

        if settings.DEBUG:
            user.activate()
            self.activate()

        return user
Пример #19
0
class Payment(_Model):
    from django.db.models import fields as _field
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion

    user = _related.ForeignKey(
        'entry.User',
        on_delete=_deletion.DO_NOTHING,
        verbose_name="Платильщик",
        null=True,
        blank=True,
    )

    discount = _related.ForeignKey(
        'pay.Discount',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=True,
    )

    info = _field.TextField(
        "Информация о платеже",
        null=False,
        blank=False,
        default="{}",
    )

    from pay.models.detail.model import PaymentDetails as _Details
    details = _related.OneToOneField(
        _Details,
        on_delete=_deletion.PROTECT,
        verbose_name="Детали",
        related_name="payment",
    )

    @property
    def company(self):
        return self.details.company if self.details else None

    @property
    def rate(self):
        return self.details.rate if self.details else None

    @property
    def time_left(self):
        from datetime import datetime

        if self.details and self.rate:
            # Cast details start to native datetime
            return self.details.start.replace(
                tzinfo=None) + self.rate.lifetime - datetime.now()

        return -0

    time_left.fget.short_description = u"Остаток времени по текущему тарифу"

    def __str__(self):
        return "Оплата от пользователя [%s] за компанию [%s] по тарифу [%s]." % (
            str(self.user), str(self.company), str(self.rate))

    class Meta:
        verbose_name = "Оплата"
        verbose_name_plural = "Оплаты"
Пример #20
0
class Department(_Model):
    from django.db.models import fields as _field
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion

    name = _field.CharField(
        verbose_name='Название отдела',
        max_length=255,
        null=False,
        blank=False,
    )

    company = _related.ForeignKey(
        'holding.Company',
        verbose_name='Компания',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=True,
        related_name="departments",
    )

    is_protected = _field.BooleanField(
        verbose_name='Неудаляемый отдел',
        default=False,
    )

    @property
    def employee_amount(self):
        return self.employees.count()

    employee_amount.fget.short_description = "Кол-во сотрудников"

    def __str__(self):
        return self.name

    def delete(self, **kwargs):
        if self.is_protected:
            raise _APIException({
                'detail': 'Protected',
                'protected': True,
            }, status_code=403)

        super(Department, self).delete(**kwargs)

    class Meta:
        verbose_name = "Отдел"
        verbose_name_plural = "Отделы"

    def attach_position(self, position):
        from holding.models import PositionToDepartment

        position.save()

        old_connection = PositionToDepartment.objects.filter(position_id=position.id, department_id=self.id).first()

        if old_connection:
            old_connection.save(department=self)
        else:
            PositionToDepartment(department=self, position=position).save()

        return self

    def create_position(self, name, **kwargs):
        from holding.models import Position

        if not self.id:
            self.save()

        position = Position(
            name=name,
            company=kwargs.get('company') if kwargs.get('company') else self.company,
            is_protected=kwargs.get('is_protected', False),
        )

        self.attach_position(position)

        return position
Пример #21
0
class Logbook(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field
    from app.fields import timezone as _timezone

    employee = _related.ForeignKey(
        'holding.Employee',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=False,  # For admin panel?
        related_name="logbooks",
    )

    start = _field.DateTimeField("Начало отрезка")
    end = _field.DateTimeField("Конец отрезка")

    activity = _field.PositiveSmallIntegerField(
        verbose_name="Активность",
        default=0,
    )

    mood = _field.PositiveSmallIntegerField(
        verbose_name="Настроение",
        default=0,
    )

    fatigue = _field.PositiveSmallIntegerField(
        verbose_name="Усталость",
        default=0,
    )

    timezone = _timezone.TimeZoneField(
        verbose_name="Временная зона",
        null=True,
        blank=True,
    )

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        if self.timezone is None:
            self.timezone = self.company.timezone

        return super(Logbook, self).save(force_insert, force_update, using,
                                         update_fields)

    @property
    def employee_fullname(self):
        return "%s %s" % (self.employee.first_name, self.employee.last_name)

    employee_fullname.fget.short_description = "Сотрудник"

    @property
    def company(self):
        return self.employee.company

    company.fget.short_description = "Компания"

    @property
    def company_name(self):
        return self.company.name

    company_name.fget.short_description = "Компания"

    def __str__(self):
        return "%s %s [%s]:(%s - %s)" % (
            self.employee.first_name,
            self.employee.last_name,
            self.start.date(),
            self.start.time(),
            self.end.time(),
        )

    class Meta:
        verbose_name = "Показатель сотрудника"
        verbose_name_plural = "Показатели сотрудников"
Пример #22
0
class Camera(_Model):
    from django.db.models.fields import related as _related
    from django.db.models import deletion as _deletion
    from django.db.models import fields as _field
    from app.fields import timezone as _timezone

    name = _field.CharField(
        verbose_name="Название",
        max_length=128,
        null=False,
        blank=False,
    )

    ip_address = _field.GenericIPAddressField(
        verbose_name="IP адрес",
        max_length=64,
    )

    login = _field.CharField(
        verbose_name="Логин",
        max_length=256,
        null=False,
        blank=False,
    )

    password = _field.CharField(
        verbose_name="Пароль",
        max_length=256,
        null=False,
        blank=True,
        default="",
    )

    is_active = _field.BooleanField(
        verbose_name="Активна",
        null=False,
        blank=False,
        default=True,
    )

    company = _related.ForeignKey(
        'holding.Company',
        on_delete=_deletion.CASCADE,
        null=False,
        blank=False,
        related_name="cameras",
    )

    zone = _related.ForeignKey(
        'cam.Zone',
        on_delete=_deletion.SET_NULL,
        null=True,
        blank=True,
        related_name="cameras",
    )

    timezone = _timezone.TimeZoneField(
        "Временная зона",
        null=True,
        blank=True,
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "Камера"
        verbose_name_plural = "Камеры"