Django删除钱包报错ValueError:Field 'id'期望数字却获'Btc'
Django删除钱包地址时ValueError错误排查
在Django模板展示钱包地址列表,点击删除按钮时触发错误:ValueError: Field 'id' expected a number but got 'Btc',但手动在删除视图URL中输入地址ID可成功删除。以下是错误栈及相关代码的分析和解决方案:
错误栈
Traceback (most recent call last): File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\fields\__init__.py", line 2018, in get_prep_value return int(value) The above exception (invalid literal for int() with base 10: 'Btc') was the direct cause of the following exception: File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\core\handlers\exception.py", line 55, in inner response = get_response(request) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\contrib\auth\decorators.py", line 23, in _wrapped_view return view_func(request, *args, **kwargs) File "C:\Users\admin\Documents\Django\crypto\dashboard\views.py", line 275, in del_wallet wallet.delete() File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\base.py", line 1137, in delete return collector.delete() File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\deletion.py", line 475, in delete query.update_batch( File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\sql\subqueries.py", line 78, in update_batch self.get_compiler(using).execute_sql(NO_RESULTS) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\sql\compiler.py", line 1819, in execute_sql cursor = super().execute_sql(result_type) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\sql\compiler.py", line 1382, in execute_sql sql, params = self.as_sql() File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\sql\compiler.py", line 1785, in as_sql val = field.get_db_prep_save(val, connection=self.connection) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\fields\related.py", line 1146, in get_db_prep_save return self.target_field.get_db_prep_save(value, connection=connection) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\fields\__init__.py", line 925, in get_db_prep_save return self.get_db_prep_value(value, connection=connection, prepared=False) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\fields\__init__.py", line 2703, in get_db_prep_value value = self.get_prep_value(value) File "C:\Users\admin\Documents\Django\env\lib\site-packages\django\db\models\fields\__init__.py", line 2020, in get_prep_value raise e.__class__( Exception Type: ValueError at /dashboard/wallet/2/delete/ Exception Value: Field 'id' expected a number but got 'Btc'.
相关代码
views.py
@login_required def wallet(request): user = request.user wallet=Wallet(user=user) object_list = Wallet.objects.filter(user=user) # Paginator paginator = Paginator(object_list, 2) page = request.GET.get('page') try: ref = paginator.page(page) except PageNotAnInteger: ref = paginator.page(1) except EmptyPage: ref = paginator.page(paginator.num_pages) if request.method == 'POST': if 'add' in request.POST: form = WalletForm(request.POST, instance=wallet) if form.is_valid(): form.save() messages.success(request, ("New wallet address successfully added.")) return redirect("dashboard:wallet") else: form = WalletForm(instance=user) context = { 'form': form, 'ref': ref, } return render(request, 'dashboard/wallet.html', context) @login_required def del_wallet(request, pk): wallet = get_object_or_404(Wallet, id=pk) wallet.delete() return redirect("dashboard:wallet")
urls.py
urlpatterns = [ path('wallet', wallet, name="wallet"), path('wallet/<str:pk>/delete/', del_wallet, name="del_wallet"), ]
wallet.html
<h3 class="h5 text-primary pt-1 pt-lg-3 mt-4">Available Wallets</h3> <div class="table-responsive"> <table class="table table-dark table-striped"> <thead> <tr> <th>SN</th> <th>Type</th> <th>Address</th> <th>Delete</th> </tr> </thead> <tbody> {% for i in ref %} <tr> <td style="line-height: 1.3; padding-top: 1.6em;">{{ forloop.counter }}</td> <td style="padding-top: 20px;">{{ i.get_type_display }}</td> <td style="padding-top: 20px;">{{ i.address }}</td> <td class="view" data-bs-toggle="modal" data-bs-target="#wallet{{ i.pk }}"> <a style="text-decoration: none;" href="#wallet{{ i.pk }}"> Delete </a> </td> </tr> <!-- DELETE MODAL --> <div class="modal fade" id="wallet{{ i.pk }}" tabindex="-1" role="dialog" style="margin-top: 10em;"> <div class="modal-dialog modal-sm" role="document"> <div class="modal-content" style="background: #141822;"> <div class="modal-body"> <h6>Confirm Delete</h6> <p>Are you sure you want to delete <span style="color: rgb(10, 223, 165);"> {{ i.type }} - {{ i.address }} </span> wallet? </p> <button type="submit" class="btn btn-primary btn-sm w-100"> <a href="/dashboard/wallet/{{ i.pk }}/delete/" style="text-decoration: none;"> Confirm </a> </button><br> <button type="button" class="btn btn-warning btn-sm w-100 mt-2" data-bs-dismiss="modal"> Close </button> </div> </div> </div> </div> {% empty %} <tr> <td>You haven't added a wallet address yet.</td> <td></td> <td></td> <td></td> </tr> {% endfor %} </tbody> </table> </div>
models.py
class Wallet(models.Model): wallet = ( ('Btc', 'Bitcoin'), ('Eth', 'Ethereum'), ('Trc20', 'Tether-UDST'), ('Ltc', 'Litecoin') ) user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) type = models.CharField(choices=wallet, default='Btc') address = models.CharField(max_length=80)
错误原因分析
级联删除配置错误:错误栈显示在执行
wallet.delete()时,Django尝试将某个外键字段的值设置为字符串'Btc',但该字段需要整数类型的ID。这说明项目中存在其他关联到Wallet模型的模型(如交易记录模型),其外键字段的on_delete参数被错误设置为models.SET('Btc'),而非合法的选项(如SET_NULL、CASCADE等)。前端按钮类型干扰:模板中确认删除的按钮使用了
type="submit",会触发页面上的表单提交(如添加钱包的表单),可能导致请求参数混乱,干扰正常的删除跳转。URL参数类型不严谨:
urls.py中删除路径的pk参数使用<str:pk>,而Wallet的id是整数类型,容易接受非整数的非法参数。
解决方案
1. 修复关联模型的级联删除配置
检查所有关联Wallet的外键字段,修正on_delete参数:
- 如果允许外键为NULL:
wallet = models.ForeignKey(Wallet, on_delete=models.SET_NULL, null=True) - 如果需要设置默认钱包,需传入可调用对象返回合法的ID:
def get_default_wallet_id(): return Wallet.objects.get_or_create(type='Btc', user=request.user)[0].id # 按需调整用户逻辑 wallet = models.ForeignKey(Wallet, on_delete=models.SET(get_default_wallet_id), default=get_default_wallet_id)
2. 修改前端按钮类型
将模态框中的确认按钮改为type="button",或直接使用<a>标签替代按钮,避免触发表单提交:
<!-- 方式1:修改按钮类型 --> <button type="button" class="btn btn-primary btn-sm w-100"> <a href="/dashboard/wallet/{{ i.pk }}/delete/" style="text-decoration: none;"> Confirm </a> </button> <!-- 方式2:直接使用a标签 --> <a href="/dashboard/wallet/{{ i.pk }}/delete/" class="btn btn-primary btn-sm w-100" style="text-decoration: none;"> Confirm </a>
3. 严谨设置URL参数类型
将urls.py中的删除路径参数改为<int:pk>,限制仅接受整数ID:
path('wallet/<int:pk>/delete/', del_wallet, name="del_wallet"),
内容的提问来源于stack exchange,提问作者Buchii
相关产品推荐
相关产品推荐

