arteria / django-openinghours

Allows to define opening hours and to verify if something, for example a store, is currently open.
MIT License
57 stars 38 forks source link

how to make query that returns companies that are open? #31

Open michaelhjulskov opened 6 years ago

michaelhjulskov commented 6 years ago

I would like to do something like this: open_shops = Shop.objects.filter(is_open=True) But how ? :)

and I'd like to add is_open to my model.

update: Im thinking something like adding this to my Shop model:

@property
def tz_info(self):
    return geocoders.GoogleV3().timezone((self.location.y,self.location.x))

@property
def is_open(self):
    now = datetime.now(tz=self.tz_info)
    now_time = time(now.hour, now.minute, now.second)
    if not ClosingRules.objects.filter(company=self, start__lte=now, end__gte=now).count():
        ohs = OpeningHours.objects.filter(company=self)
        for oh in ohs:
            is_open = False
            # start and end is on the same day
            if (oh.weekday == now.isoweekday() and oh.from_hour <= now_time and now_time <= oh.to_hour):
                is_open = oh

            # start and end are not on the same day and we test on the start day
            if (oh.weekday == now.isoweekday() and oh.from_hour <= now_time and ((oh.to_hour < oh.from_hour) and (now_time < time(23, 59, 59)))):
                is_open = oh

            # start and end are not on the same day and we test on the end day
            if (oh.weekday == (now.isoweekday() - 1) % 7 and oh.from_hour >= now_time and oh.to_hour >= now_time and oh.to_hour < oh.from_hour):
                is_open = oh
                # print " 'Special' case after midnight", oh

            if is_open is not False:
                return oh
    return False
imposeren commented 6 years ago

You can try using Q and F objects:

from django.db.models import Q, F

Company.objects.filter(
    ~Q(closingrules__start__lte=now, closingrules_set__end__gte=now)
    &
    (
        Q(
            openinghours__weekday=now.isoweekday(),
            openinghours__from_hour__lte=now_time,
            openinghours__to_hour__gte=now_time,
        ) | Q(
            openinghours__weekday=now.isoweekday(),
            openinghours__from_hour__lte=now_time,
            openinghours__to_hour__lt=F('openinghours__from_hour'),
        ) | Q(
            openinghours__weekday=(now.isoweekday() - 1) % 7,
            openinghours__from_hour__gte=now_time,
            openinghours__to_hour__gte=now_time,
        )
    )
)

If you really need it to be like "property" then you can also try annotating queryset