Home > OS >  Specify exact opening hours for buisness
Specify exact opening hours for buisness

Time:09-22

im trying to create custom field for django model. I need to store opening hours for every day of the week.

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}'

I have to store opening hours in a field like

opening_hours = models.CustomField()

CodePudding user response:

If you don't want a separate table and you are using a postgreSQL database, you could combine the TimeField with an ArrayField. It would look something like this.

from django.contrib.postgres.fields import ArrayField
from django.db import models

class Restaurant(models.Model):
    opening_hours = ArrayField(models.TimeField(), size=7)

You would then access the hours for any day of the week using an index. Assuming Sunday as the first day of the week you could access Tuesday's opening hours with

restaurant.opening_hours[2]  # Sunday = 0, Monday = 1

To expand on this idea, you could add the indexes with names to the Restaurant model so that it would be even more obvious in your code exactly what you're getting.

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]

CodePudding user response:

You can define your own custom field that will hold all the opening hours per day. Here, we will use an OpeningHours class that will hold the opening time per day of type datetime.time which means entering an invalid time e.g. 12:61 would fail validation. Then, we will store it as a space-separated string to the database field opening_hours e.g.

12:00 15:00 18:00 18:30 09:00 12:00 08:45

All we need to do is to configure:

  • Saving of the custom field to the database from an instance of type OpeningHours to that space-separated string of times per day via get_prep_value()
  • Retrieving the custom field from the database from that space-separated string to an instance of OpeningHours via 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}'

Creating a new Restaurant would require an OpeningHours object to be set to the custom opening_hours field:

>>> 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>}

Reading the opening_hours field is just like reading an ordinary OpeningHours object:

>>> 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)

To update the time for a particular day, just update the corresponding field and save.

>>> # 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
  • Related