Django中传递变量作为relativedelta关键字参数触发TypeError求助
问题:Django信号接收器中relativedelta传参报错TypeError: keywords must be strings
我在Django项目的post_save信号接收器create_forecasted里,尝试用变量作为关键字参数传给relativedelta方法,核心代码如下:
@receiver(post_save, sender=BudgetTransaction) def create_forecasted(sender, instance, created, **kwargs): if instance.transaction_type == "EC": return True if created: today = instance.next_date last_day = date(today.year, 12, 31) this_month = today.month weeks_left = int((last_day - today).days / 7) fortnights_left = int(weeks_left / 2) months_left = 12 - this_month if instance.frequency == 'weeks': create_range = weeks_left elif instance.frequency == 'fort': create_range = fortnights_left else: create_range = months_left loop = 1 for i in range(create_range): if instance.frequency == 'fort': true_frequency = 'weeks' true_loop = loop * 2 elif instance.frequency == '4week': true_frequency = 'weeks' true_loop = loop * 4 else: true_frequency = instance.frequency true_loop = loop ### 问题出在这行 ### next_month = today + relativedelta(**{true_frequency: true_loop}) date_string = next_month.strftime("%Y-%m-%d") BudgetTransaction.objects.bulk_create([BudgetTransaction( owner=instance.owner, transaction_amount=instance.transaction_amount, transaction_name=instance.transaction_name, transaction_type=instance.transaction_type, next_date=date_string, frequency=instance.frequency, )]) loop += 1
代码在网站运行时正常,但执行测试时触发错误:
Error Traceback (most recent call last): File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\bf_app\tests\test_models.py", line 26, in test_transaction_has_owner transaction = TransactionFactory(owner=user) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\base.py", line 40, in __call__ return cls.create(**kwargs) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\base.py", line 528, in create return cls._generate(enums.CREATE_STRATEGY, kwargs) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\django.py", line 117, in _generate return super()._generate(strategy, params) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\base.py", line 465, in _generate return step.build() File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\builder.py", line 262, in build instance = self.factory_meta.instantiate( File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\base.py", line 317, in instantiate return self.factory._create(model, *args, **kwargs) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\factory\django.py", line 166, in _create return manager.create(*args, **kwargs) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\django\db\models\manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\django\db\models\query.py", line 514, in create obj.save(force_insert=True, using=self.db) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\django\db\models\base.py", line 806, in save self.save_base( File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\django\db\models\base.py", line 872, in save_base post_save.send( File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\django\dispatch\dispatcher.py", line 176, in send return [ File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\venv\lib\site-packages\django\dispatch\dispatcher.py", line 177, in <listcomp> (receiver, receiver(signal=self, sender=sender, **named)) File "C:\Users\Mitchell\PycharmProjects\BudgieFinance_TW\bf_app\models.py", line 82, in create_forecasted next_month = next_date + relativedelta(**{true_frequency: true_loop}) TypeError: keywords must be strings
解决方案
错误原因
测试场景下,true_frequency变量可能不是字符串类型,或者TransactionFactory生成的frequency字段值不符合预期,导致传给relativedelta的关键字参数不是合法字符串。relativedelta要求关键字参数是weeks、months这类字符串。
修复步骤
- 确保
true_frequency是合法字符串
新增校验逻辑,强制转换类型并过滤无效参数; - 检查测试工厂配置
确保TransactionFactory生成的frequency字段是合法字符串(比如'weeks'、'fort'、'4week'),不要传入非字符串类型。
修改后的代码片段
# 在循环内添加校验逻辑 if instance.frequency == 'fort': true_frequency = 'weeks' true_loop = loop * 2 elif instance.frequency == '4week': true_frequency = 'weeks' true_loop = loop * 4 else: true_frequency = instance.frequency true_loop = loop # 新增:确保true_frequency是字符串且为relativedelta支持的参数 valid_relativedelta_keys = {'weeks', 'months'} # 强制转换为字符串,避免非字符串类型 true_frequency = str(true_frequency) if true_frequency not in valid_relativedelta_keys: # 跳过无效情况,避免报错 loop += 1 continue # 正常计算日期 next_month = today + relativedelta(**{true_frequency: true_loop})
另外,检查你的TransactionFactory,确保frequency字段的默认值或传入值都是字符串,比如:
class TransactionFactory(factory.django.DjangoModelFactory): class Meta: model = BudgetTransaction # 确保frequency是字符串类型 frequency = factory.Faker('word', ext_word_list=['weeks', 'fort', '4week']) # 其他字段...
内容的提问来源于stack exchange,提问作者MitchW
相关产品推荐
相关产品推荐

