【问题标题】:cannot unpack non-iterable datetime.date object无法解压不可迭代的 datetime.date 对象
【发布时间】:2019-11-29 15:28:12
【问题描述】:

我正在构建一个预订表单,并希望允许用户从未来 60 天内的可用日期中选择一个预订日期。

我通过以下方式获得接下来的 60 天:

base = datetime.date.today()
date_list = [base + datetime.timedelta(days=x) for x in range(60)]

然后我减去存储在数据库中的已预订日期:

bookings = list(Booking.objects.all())
primarykeys = []
unav = []

for b in bookings:
    primarykeys.append(b.pk)

for p in primarykeys:
    unav.append(Booking.objects.get(pk=p).booking_date)

for date in unav:
    if date in date_list:
        date_list.remove(date)

然后我将结果更改为表单的元组(不确定这是否正确?):`

date_list = tuple(date_list)

然后我将它传递到表单字段中:

booking_date = forms.ChoiceField(choices=date_list, required=True)

这给了我一个cannot unpack non-iterable datetime.date object的错误

现在我被难住了……我该怎么做?我有一种感觉,我走错了路。

提前致谢

【问题讨论】:

    标签: python django


    【解决方案1】:

    Django Form fields 的文档说明如下:

    选择

    可以使用 2 元组的可迭代对象作为此字段的选择,也可以是返回此类可迭代对象的可调用对象。这个论点接受 与模型字段的选择参数相同的格式。查看型号 有关选择的字段参考文档以获取更多详细信息。如果 参数是一个可调用的,每次字段的形式是评估它 初始化。默认为空列表。

    看起来你传递的是这种格式的元组:

    (date object, date object, ...)
    

    但是您需要传递类似 2 元组列表的内容,每个元组的第一个元素是为每个选择存储的值,第二个元素是在表单中显示给用户的值:

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

    将您的代码更改为以下内容,看看是否适合您:

    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])
    

    我使用集合来更简单地确保唯一值并在没有多个for 循环的情况下将两者相减。您可以使用values_listflat=True 来获取所有现有的预订日期,然后创建一个2 元组列表date_choices,以实际的日期时间对象作为值,并以您使用@ 选择的任何格式显示字符串表示987654330@.

    然后使用sorted根据第一个键按日期升序对日期进行排序,因为使用集合会打乱排序顺序。

    然后看看this question,看看如何将这些选项从您的视图传递到表单中,因为我认为在定义 Form 类本身时尝试动态设置选项并不好。

    【讨论】:

    • 谢谢伙计,多么棒的全面答案,你能告诉我为什么在 forms.py 中设置选项不是一个好主意吗?如果我在 Form 类本身之外但在同一个文件中设置选项呢?
    • 这确实与该代码何时运行以实际设置选择有关。我想你想在表单初始化时设置它。也许您可以覆盖表单的 __init__ 方法并将代码放在那里,以便在实例化时设置选择,但是我觉得您不妨做那个最佳答案的工作并从视图中传递选择作为表单创建时所期望的参数。你可以玩弄它,看看它是否适合你。我发现使用 Django 通常有多种方法可以做某事,每种方法都有自己的优势。
    • @alvo 我链接的那个答案有一个特殊要求,即某些信息必须来自请求,因此要在表单中访问它,您必须以某种方式从处理该请求的视图中传递它request 对象。由于您只是获得 all Booking.booking_date 值,我认为在表单的 __init__ 中包含该代码并在每次创建表单时为该字段设置选项可能会起作用,因为这些日期会随着时间而改变。也许先尝试一下,看看它是否有效。
    • 非常感谢您提供的额外信息,一定会考虑将代码添加到表单init
    猜你喜欢
    • 2020-01-28
    • 2019-04-22
    • 2020-07-21
    • 2020-04-08
    • 2021-07-10
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多