Pierre de LESPINAY
Pierre de LESPINAY

Reputation: 46208

Django - Opening time formset

Context

I need to build a formset to allow opening hours to be set for a week.

Status

Here is my model for opening times:

WEEKDAYS = [
  (1, _("Monday")),
  (2, _("Tuesday")),
  (3, _("Wednesday")),
  (4, _("Thursday")),
  (5, _("Friday")),
  (6, _("Saturday")),
  (7, _("Sunday")),
]

class OpeningHours(models.Model):
    user = models.ForeignKey(User)
    weekday = models.IntegerField(choices=WEEKDAYS)
    from_hour = models.TimeField()
    to_hour = models.TimeField()
    class Meta:
        unique_together = (('user', 'weekday'),)

Here is how I generate a formset for a default week setting

UserOpeningHoursFormSet = formset_factory(UserOpeningHoursForm, extra=0)
hours = [{
        'weekday': day,
        'from_hour': '08:00',
        'to_hour': '18:00',
    } for day in range(1, 8)]
formset = UserOpeningHoursFormSet(initial=hours)

Here is how I get opening hours for the current user

user_hours = request.user.openinghours_set.all()

Question

How can I put the user_hours into my formset ?


Edit

Example, let's say the user already has the hours for Monday and Thursday set in the db, the form should resemble:

weekday: Monday
from_hour: '09:00' # user_set
to_hour: '19:00' # user_set

weekday: Tuesday
from_hour: # default initial value
to_hour: # default initial value

weekday: Wednesday
from_hour: # default initial value
to_hour: # default initial value

weekday: Thursday
from_hour: '13:00' # user_set
to_hour: '15:00' # user_set

weekday: Friday
from_hour: # default initial value
to_hour: # default initial value

weekday: Saturday
from_hour: # default initial value
to_hour: # default initial value

Upvotes: 3

Views: 612

Answers (3)

XORcist
XORcist

Reputation: 4367

Expanding on @Rohan's answer:

I don't think modelformset is neccessary, just construct the hours like this

hours = [
    {'weekday': day, 'from_hour': '08:00', 'to_hour': '18:00'} 
    for day in range(1, 8) if not any(request.user.openinghours_set.filter(weekday=day))
    else
    {'weekday': day, 'from_hour': request.user.openinghours_set.filter(weekday=day).from_hour,
     'to_hour': request.user.openinghours_set.filter(weekday=day).to_hour}
]

Obviously, this is inefficient as it constructs one or three queryset(s) for each day, so rewriting it like this:

hours = []

openinghours_set = list(request.user.openinghours_set.all())
for day in range(1, 8):
    for openinghours in openinghours_set:
        if openinghours.weekday == day:
            hours.append({ fill from *openinghours* })
            break
    else:
        hours.append({ fill with default values })

Upvotes: 2

Pierre de LESPINAY
Pierre de LESPINAY

Reputation: 46208

Here is what I ended up with:

user_hours = request.user.openinghours_set
hours = []
for day_id in range(0, 6):
    item = {'weekday': day_id, 'from_hour': '08:00', 'to_hour': '18:00'}
    if any(user_hours.filter(weekday=day_id)):
        my_item = user_hours.get(weekday=day_id)
        item['from_hour'] = my_item.from_hour.strftime('%H:%M')
        item['to_hour'] = my_item.to_hour.strftime('%H:%M')
    hours.append(item)

I would have preferred a more pythonic version...

Upvotes: 0

Rohan
Rohan

Reputation: 53376

You can use modelformset and provide appropriate queryset.

formset = UserOpeningHoursModelFormSet(queryset=request.user.openinghours_set.filter())

There are also some other ways to change the queryset.

EDIT:

May be you can make use of max_num parameter while creating the formset instance along with initial. So you will get forms from existing instances and if instances are not enough, new forms will be created with data from initial dict.

    UserOpeningHoursFormSet = modelformset_factory(UserOpeningHoursForm, extra=7, max_num=7)
    formset = UserOpeningHoursModelFormSet(initial=hours,
                 queryset=request.user.openinghours_set.filter())

I haven't verified this, so I suspect it may add forms for each initial data items. So in worst case you need to create hours list with skipping for days for which hours are set.

Upvotes: 0

Related Questions