Django API中functools.partial结合map出现参数重复值错误求助
Django REST Framework中map+partial传参报错:TypeError: get_counts() got multiple values for argument 'id'
问题场景
在DRF API端点中尝试用map结合functools.partial传递额外参数,测试代码正常运行,但API代码触发参数冲突错误。
测试代码(正常运行)
>>> tt [(datetime.datetime(2023, 4, 1, 0, 0), datetime.datetime(2023, 4, 10, 0, 0)), (datetime.datetime(2023, 4, 10, 0, 0), datetime.datetime(2023, 4, 1, 0, 0))] >>> def t(d1: datetime.datetime, d2: datetime.datetime, i: int): ... print(f"First: {d1.strftime('%Y-%m-%d')} & Second: {d2.strftime('%Y-%m-%d')} w/ ID: {i}") >>> list(map(partial(t, i=10), *tt)) First: 2023-04-01 & Second: 2023-04-10 w/ ID: 10 First: 2023-04-10 & Second: 2023-04-01 w/ ID: 10 [None, None]
API代码(报错位置标注)
from rest_framework.decorators import api_view from rest_framework.response import Response import datetime import functools from .models import Entity, OtherEntity @api_view(["GET"]) def get_registration_counts(request, start: str, stop: str) -> Response: date_format = "%Y-%m-%d" # 验证start和stop参数有效性,无效则返回HTTP 400 datasets = [] def get_counts(d1: datetime.datetime, d2: datetime.datetime, id: int) -> int: r = Entity.objects.filter(some_date__gte=d1, some_date__lte=d2, fk_id=id) c = r.count() return c # 计算日期范围 dates = [(some_start_date1, some_end_date1), (some_start_date2, some_end_date2)] some_values = OtherEntity.objects.filter(active=1).values("id", "name") for v in some_values: # 报错位置: counts = list(map(functools.partial(get_counts, id=v["id"]), *dates)) datasets.append(counts) # ...其他逻辑 # ...其他逻辑
报错信息
Exception Type: TypeError
Exception Value: get_counts() got multiple values for argument 'id'
问题原因
你混淆了map的两种用法,测试代码与API代码的map调用逻辑完全不匹配:
- 测试代码逻辑:
*tt将列表拆分为两个独立可迭代对象,map并行遍历这两个对象,每次取两个元素作为t的前两个位置参数,第三个参数i由partial以关键字参数绑定,无参数冲突。 - API代码逻辑错误:
你实际需求是遍历dates中的每个(start, end)元组,调用get_counts(start, end, id=v["id"]),但错误使用*dates导致:*dates将dates拆分为多个独立可迭代对象(每个元组对应一个)map并行遍历这些对象,每次传入N个位置参数(N为dates的长度)- 若N>2,第三个位置参数会被当作
id的位置参数传入,而partial已经以关键字参数绑定了id,导致参数重复传递,触发错误。
解决方法
根据你的实际需求(遍历dates中的每个元组并传入id),调整map用法:
方法1:用lambda拆包元组
counts = list(map(lambda dt: get_counts(dt[0], dt[1], id=v["id"]), dates))
方法2:结合partial与lambda拆包
bound_get_counts = functools.partial(get_counts, id=v["id"]) counts = list(map(lambda dt: bound_get_counts(*dt), dates))
方法3:调整参数顺序适配partial(若需匹配测试代码逻辑)
修改get_counts参数顺序,将id放在首位,再用zip(*dates)对齐参数:
def get_counts(id: int, d1: datetime.datetime, d2: datetime.datetime) -> int: r = Entity.objects.filter(some_date__gte=d1, some_date__lte=d2, fk_id=id) return r.count() counts = list(map(functools.partial(get_counts, v["id"]), *zip(*dates)))
内容的提问来源于stack exchange,提问作者ablaze
相关产品推荐
相关产品推荐

