Укажите точные часы работы предприятия
Я пытаюсь создать пользовательское поле для модели django. Мне нужно хранить часы работы для каждого дня недели.
class Restaurant(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
city = models.CharField(max_length=15)
street = models.CharField(max_length=15)
house_number = models.CharField(max_length=3)
flat_number = models.CharField(max_length=3, default='0')
phone_number = models.CharField(max_length=12)
image = models.ImageField()
rating = models.FloatField(validators=[validate_rating_number])
def __str__(self):
return f'{self.name}, {self.city}'
Мне нужно хранить часы работы в поле типа
opening_hours = models.CustomField()
Если вам не нужна отдельная таблица и вы используете базу данных PostgreSQL, вы можете объединить TimeField с ArrayField. Это выглядело бы примерно так.
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Restaurant(models.Model):
opening_hours = ArrayField(models.TimeField(), size=7)
Затем можно получить доступ к часам работы для любого дня недели, используя индекс. Приняв воскресенье за первый день недели, вы можете получить доступ к часам работы во вторник с помощью
restaurant.opening_hours[2] # Sunday = 0, Monday = 1
Чтобы расширить эту идею, можно добавить индексы с именами в модель Restaurant, чтобы в коде было еще более очевидно, что именно вы получаете.
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Restaurant(models.Model):
SUN, MON, TUE, WED, THU, FRI, SAT = 0, 1, 2, 3, 4, 5, 6
opening_hours = ArrayField(models.TimeField(), size=7)
r = Restaurant.objects.first()
r.opening_hours[r.TUE]
Вы можете определить собственное пользовательское поле, которое будет содержать все часы работы в день. Здесь мы будем использовать класс OpeningHours
, который будет хранить время работы в день типа datetime.time, что означает, что ввод недопустимого времени, например 12:61
, не пройдет проверку. Затем мы сохраним его как строку, разделенную пробелами, в поле базы данных opening_hours
, например
12:00 15:00 18:00 18:30 09:00 12:00 08:45
Все, что нам нужно сделать, это сконфигурировать:
- Сохранение пользовательского поля в базу данных из экземпляра типа
OpeningHours
в строку с разделителем пространства раз в день черезget_prep_value()
- Извлечение пользовательского поля из базы данных из строки, разделенной пробелами, в экземпляр типа
OpeningHours
черезfrom_db_value()
.
models.py
from datetime import datetime
from django.core.exceptions import ValidationError
class OpeningHours:
FORMAT = '%H:%M'
def __init__(self, mon, tue, wed, thu, fri, sat, sun):
self.mon = datetime.strptime(mon, self.FORMAT).time()
self.tue = datetime.strptime(tue, self.FORMAT).time()
self.wed = datetime.strptime(wed, self.FORMAT).time()
self.thu = datetime.strptime(thu, self.FORMAT).time()
self.fri = datetime.strptime(fri, self.FORMAT).time()
self.sat = datetime.strptime(sat, self.FORMAT).time()
self.sun = datetime.strptime(sun, self.FORMAT).time()
def __str__(self):
return ' '.join(
dt_time.strftime(self.FORMAT)
for dt_time in (
self.mon,
self.tue,
self.wed,
self.thu,
self.fri,
self.sat,
self.sun,
)
)
class OpeningHoursField(models.CharField):
description = "Opening time per day"
def from_db_value(self, value, expression, connection):
return self.to_python(value)
def to_python(self, value):
if value is None or isinstance(value, OpeningHours):
return value
try:
obj = OpeningHours(*value.split())
except Exception:
raise ValidationError("Invalid opening time")
else:
return obj
def get_prep_value(self, value):
return str(value)
class Restaurant(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
city = models.CharField(max_length=15)
opening_hours = OpeningHoursField(max_length=100)
def __str__(self):
return f'{self.name}, {self.city}'
Создание нового Restaurant
потребует установки объекта OpeningHours
в пользовательское поле opening_hours
:
>>> from my_app.models import *
>>> opening_hours = OpeningHours(mon="12:00", tue="15:00", wed="18:00", thu="18:30", fri="09:00", sat="12:00", sun="08:45")
>>> obj = Restaurant.objects.create(name="Burger King", city="London", opening_hours=opening_hours)
>>> obj.save()
>>> obj.__dict__
{'_state': <django.db.models.base.ModelState object at 0x7fe3c5b4cb50>, 'id': 1, 'name': 'Burger King', 'city': 'London', 'opening_hours': <my_app.models.OpeningHours object at 0x7fe3c5b4c1f0>}
Чтение поля opening_hours
происходит так же, как и чтение обычного объекта OpeningHours
:
>>> print(obj.opening_hours)
12:00 15:00 18:00 18:30 09:00 12:00 08:45
>>> obj.opening_hours.mon
datetime.time(12, 0)
>>> obj.opening_hours.tue
datetime.time(15, 0)
>>> obj.opening_hours.wed
datetime.time(18, 0)
>>> obj.opening_hours.thu
datetime.time(18, 30)
>>> obj.opening_hours.fri
datetime.time(9, 0)
>>> obj.opening_hours.sat
datetime.time(12, 0)
>>> obj.opening_hours.sun
datetime.time(8, 45)
Чтобы обновить время для определенного дня, просто обновите соответствующее поле и сохраните.
>>> # Display old value
>>> print(Restaurant.objects.first().opening_hours)
12:00 15:00 18:00 18:30 09:00 12:00 08:45
>>> print(Restaurant.objects.first().opening_hours.thu)
18:30:00
>>>
>>> # Update new value for Thursday and save
>>> obj.opening_hours.thu = datetime.time(hour=1, minute=23)
>>> obj.save()
>>>
>>> # Display updated value
>>> print(Restaurant.objects.first().opening_hours)
12:00 15:00 18:00 01:23 09:00 12:00 08:45
>>> print(Restaurant.objects.first().opening_hours.thu)
01:23:00