@Arhin
Студент

Как описать хранение рабочих часов в бд?

Нужно описать такую модель, которая будет хранить рабочие часы компании на каждый день недели. В том числе сериалайзер к нему и вьюсет. При этом надо что б в при оно отображалось и принималось примерно в таком формате(не рабочие просто не выводятся):
working_hours: {
    monday: [12:30, 12:40],
    wednesday: [18:40, 19:40]
}

Я сам описал модель, где для каждого дня недели есть поле рабочий ли день, время начала, время конца. Плюс для вывода сделал поле проперти, которое собирает вывод их как в примере. Но возникли сложности с сериалайзером, который бы в таком виде принимал данные и сохранял все по своим полям.
Код приложить нет возможности.
  • Вопрос задан
  • 347 просмотров
Пригласить эксперта
Ответы на вопрос 2
JRazor
@JRazor
Senior StarkOverFlow Programmer
Модель простая - день недели, начало рабочего дня, конец рабочего дня.

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

Почитать документацию к DRF, там ничего сложного нет. Переопределение методов save, update в сериалайзерах и прочие штуки.
Ответ написан
werevolff
@werevolff
1. Рабочие часы - это тип данных str а не datetime! Почему? Потому, что Datetime в любом случае возвращает конкретную дату. Как надо себе это представлять:

start_time: str = '12:20'
end_time: str = '16:00'


Есть ещё TimeField, но тогда надо будет в поле объявлять format=

2. Есть несколько вариантов записи этих данных в модель. Самый простой - через Choices:

class WorkDay(models.Model):
    DAYS_OF_WEEK = (
        (1, _('Monday')),
        (2, _('Tuesday')),
        (3, _('Wednesday')),
        (4, _('Thursday')),
        (5, _('Friday')),
        (6, _('Saturday')),
        (7, _('Sunday')),
    )
    DAY_TYPES = (
        ('weekday', _('weekday')),
        ('holiday', _('holiday')),
    )
    day_of_the_week = models.PositiveIntegerField(
        verbose_name=_('day of the week'),
        choices=DAYS_OF_WEEK
    )
    start_time = models.CharField(
        verbose_name=_('start time'),
        max_length=5
    )
    end_time = models.CharField(
        verbose_name=_('end time'),
        max_length=5
    )
    day_type = models.CharField(
        verbose_name=_('day type'),
        max_length=255,
        choices=DAY_TYPES
    )


3. Нам может потребоваться записать в рабочий день несколько пар рабочих часов. В этом случае, наиболее верным способом я счёл бы использование ArrayField или ListField

from django.contrib.postgres.fields import ArrayField

class WorkDay(models.Model):
    DAYS_OF_WEEK = (
        (1, _('Monday')),
        (2, _('Tuesday')),
        (3, _('Wednesday')),
        (4, _('Thursday')),
        (5, _('Friday')),
        (6, _('Saturday')),
        (7, _('Sunday')),
    )
    DAY_TYPES = (
        ('weekday', _('weekday')),
        ('holiday', _('holiday')),
    )
    day_of_the_week = models.PositiveIntegerField(
        verbose_name=_('day of the week'),
        choices=DAYS_OF_WEEK
    )
    working_hours = ArrayField(
        ArrayField(
            models.CharField(
                max_length=5
            ),
            size=2
        ),
        verbose_name=_('working hours')
    )
    day_type = models.CharField(
        verbose_name=_('day type'),
        max_length=255,
        choices=DAY_TYPES
    )


4. Также, мы можем использовать JSONField (MySQL или PostgreSQL )

from django.contrib.postgres.fields import JSONField

class WorkGraph(models.Model):
    working_graph = JSONField(
        verbose_name=_('working graph'),
        default={
            'monday': {
                'hours': ['12:20', '16:00'],
                'day_type': 'weekday'
            }
        }
    )


Я бы предпочёл вариант с ArrayField.

ArrayField как и JSONField поддерживаются DRF и представляют данные в виде массивов Python, которые можно отработать через validate.

При таком подходе фронт берёт на себя построение UI, при котором пользователь просто выбирает часы и минуты в форме и добавляет их. JS строит на основе формы массив и передаёт в DRF.

И бонусом, используем валидацию для полей Django и DRF:

import re
from django.core.exceptions import ValidationError
from typing import NoReturn

def validate_working_hours(
        value: str
) -> NoReturn:
    m = re.match(
        r'^(?P<hours>\d{2}):(?P<minutes>\d{2})$',
        value
    )
    if m is None:
        raise ValidationError('please, use format HH:mm')
    else:
        hours = int(
            m.group('hours')
        )
        if hours > 23:
            raise ValidationError('hours is a value from 0 to 23')
        minutes = int(
            m.group('minutes')
        )
        if minutes > 59:
            raise ValidationError('minutes is a value from 0 to 59')
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы