6

I'm not sure this is the best title, but I'm having trouble phrasing it simply. Basically, I'm creating a model that represents a business. This includes and address, operating hours, etc. It's the operating hours that are tripping me up. I have my address

class Address(models.Model):
    --snip--
   Business = models.ForeignKey(BusinessInfo)

So each business has one or more location addresses. I'm looking to do similar with Hours

class HoursOnDay(models.Model):
    open = isOpen = models.BooleanField()
    open = models.TimeField(null=True)
    closed = models.TimeField(null=True)

What I want to enforce is that each business has to have an array of 7 HoursOnDay - one for each day of the week. I can't seem to stumble on the obvious, elegant way to do this. Is there a good way to model this in django?

2 Answers 2

5

use ManyToManyField:

class HoursOnDay(models.Model):
    is_open = models.BooleanField()
    open = models.TimeField(null=True)
    closed = models.TimeField(null=True)

class Day(models.Model):
    hours = models.ManyToManyField(HoursOnDay)

class Business(models.Model):
    days = models.ManyToManyField(Day)

if you want to have limit for 7hours and 7days you can check Limit number of model instances to be created

Sign up to request clarification or add additional context in comments.

7 Comments

And which day is which then? (Just pointing out that you need more boilerplate than shown here to make this work).
it's just example you can add the attributes that you need
This seems perfect. If I do this, would it make sense (and be the djano way!) to somewhere, perhaps in init populate the days field in the Business model with the 7 days of the week? Basically, it would be nice if a business owner is creating a new location through the admin and they are encouraged to add all 7 days.
Business.__init__() is too early for initiating the seven days (foreign keys to models that are not yet stored, don't work well). Do that in a post_create signal handler where the Business model has already been saved. Updating opening hours in a setup like this will also require quite an overhead in the update view definition. Did we also consider the number of database hits required to acess these simple properties, you need to apply some prefect_related to work-around this kind of modelling? but go ahead and make your own experiences :)
My suggestion (yes I did the other answer) is the simplest and by far the most efficient approach. It is the benchmark that all other suggestions should be compared with.
|
0

I have come across a similar problem (needed a bunch of fields for every hour of the day) and reached the following conclusion:

The most djangoish way to do this, is to not try and do anything smart. If you need a bunch of fields seven times, just copy paste the fields and give them different postfix or prefix. E.g.:

class Business(models.Model):
    --snip--
    monday_is_open = models.BooleanField()
    monday_opens_at = models.TimeField(null=True)
    monday_closes_at = models.TimeField(null=True)

    tuesday_is_open = models.BooleanField()
    tuesday_opens_at = models.TimeField(null=True)
    tuesday_closes_at = models.TimeField(null=True)

    wednesday_is_open = models.BooleanField()
    wednesday_opens_at = models.TimeField(null=True)
    wednesday_closes_at = models.TimeField(null=True)

    ...

    sunday_is_open = models.BooleanField()
    sunday_opens_at = models.TimeField(null=True)
    sunday_closes_at = models.TimeField(null=True)

Of course Americans (and others?) would start with sunday, but you get the idea.

Following this approach greatly simplifies updating opening hours. This approach (and what you requested) fail to model changing opening hours from week to week, but that is probably not your need either.

Also, if you are concerned with schema normalization, get rid of the is_open, and just use xxx_opens_at__isnull=True, xxx_closes_at__isnull=True where you would have used xxx_is_open=True.

You can still do smart stuff with iteration across the weekdays in Business.clean().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.