Reputation: 46208
I need to build a formset to allow opening hours to be set for a week.
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()
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
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
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
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