[Django]-Cannot unpack non-iterable datetime.date object

2👍

The docs for Django Form fields says the following:

choices

Either an iterable of 2-tuples to use as choices for this field, or a callable that returns such an iterable. This argument accepts the
same formats as the choices argument to a model field. See the model
field reference documentation on choices for more details. If the
argument is a callable, it is evaluated each time the field’s form is
initialized. Defaults to an empty list.

It looks like what you’re passing is a tuple in this format:

(date object, date object, ...)

But you need to be passing something like a list of 2-tuples, with the first element of each tuple being the value stored for each choice, and the second element being the value displayed to the user in the form:

[(date_object, date_string), (date_object, date_string), ...)

Change your code to the following and see if that works for you:

base = datetime.date.today()
date_set = set([base + datetime.timedelta(days=x) for x in range(60)])
booking_dates = set(Booking.objects.all().values_list('booking_date', flat=True))
valid_dates = date_set - booking_dates

date_choices = sorted([(valid_date, valid_date.strftime('%Y-%m-%d')) for valid_date in valid_dates], 
                      key=lambda x: x[0])

I’ve used sets to make it simpler to ensure unique values and subtract the two from each other without multiple for loops. You can use values_list with flat=True to get all the existing booking dates, then create a list of 2-tuples date_choices, with the actual datetime object as the value and display a string representation in whatever format you choose using strftime.

Then the dates are sorted using sorted by date ascending based on the first key, since using sets will mess up the sort order.

Then take a look at this question to see how you can pass these choices into the form from your view, as I don’t think it’s good to try to dynamically set the choices when defining the Form class itself.

Leave a comment