django ModelForm外鍵問題

news2024/9/19 19:10:14

背景

django在使用ModelForm時如果存在外鍵字段,默認是ChoiceField讓你選擇外鍵關聯表有的值,但是如果關聯表的數據很多的話選擇就很難找到選項。所以想能不能換成輸入框TextInput

舉個例子

models.py

這裏建了兩個表,把用戶表的name作爲外鍵加入詳情表

class User(models.Model):
    """ 用戶表 """
    name= models.CharField(verbose_name="用戶", max_length=32)


class Detail(models.Model):
    """ 详情表 """
    name= models.ForeignKey(to="User", to_field="id", on_delete=models.CASCADE)
    asd= models.IntegerField(verbose_name="asd")

detail_add.html

用模板渲染引擎把前端展示出來

<div class="panel-body">
                <form method="post" novalidate>
                    {% csrf_token %}

                    {% for filed in form %}
                        <div class="form-group">
                            <label>{{ filed.label }}</label>
                            {{ filed }}
                            <span style="color: red">{{ filed.errors.0 }}</span>
                        </div>
                    {% endfor %}

                    <button type="submit" class="btn btn-primary">提 交</button>
                </form>
            </div>

用了bootstrap樣式才長這樣,本來是最原始的下拉框
在这里插入图片描述

view.py

class DetailModelForm(forms.ModelForm):
	""" 定義一個ModelForm類 """
    class Meta:
        model = Detail
        fields = '__all__'



class AddView(View):
    """ 添加用戶詳情 """

    def get(self, request):
        form = DetailModelForm()
        return render(request, 'detail_add.html', {'form': form})

    def post(self, request):
        # 用户POST提交数据,数据校验
        data = request.POST
        form = DetailModelForm(data=data)
        if form.is_valid():
            # 如歌数据合法,保存到数据库
            # print(form.cleaned_data)
            form.save()
            return redirect('/index/')
        else:
            # 校验失败
            # print(form.errors)
            return render(request, 'detail_add.html', {'form': form})

問題描述及解決

修改ModelForm類把外鍵字段改成TextInput

class DetailModelForm(forms.ModelForm):
    class Meta:
        model = Detail
        fields = '__all__'
        widgets = {
            'name': forms.TextInput,
        }

報錯

雖然成功變成一個輸入框,但是輸入提交報以下錯誤

选择一个有效的选项: 该选择不在可用的选项中。

在这里插入图片描述

解決思路

雖然不知道是爲什麽也搜不到解答,感覺可能是沒能索引到外鍵的表
然後我就打個斷點debug看一下到底每一步怎麽走的

爲此我又創建一個country字段讓他作爲外鍵,依舊保持ChoiceField,看看不修改成TextInput和修改成TextInput有什麽區別

圈起來的兩個字段就是外鍵字段,可以發現在author字段是名字 但是在country字段是數字。這個數字是什麽?爲什麽是數字?查了一下數據庫發現是country的值在數據庫的id
在这里插入图片描述
那就明白了,ChoiceField字段接收到的是id但是TextInput收到的就是字符串,那我們轉換成id傳給ModelForm不就可以了

解決方案

class AddView(View):
    """ 添加用戶詳情 """

    def get(self, request):
        form = DetailModelForm()
        return render(request, 'detail_add.html', {'form': form})

    def post(self, request):
        # 用户POST提交数据,数据校验
        # 修改版本
        author = request.POST.get('author')	# 得到表單中author
        author = Author.objects.get(author=author).pk	# 得到該人的id,pk是主鍵的意思這裏用 .id 也是一樣
        data = request.POST
        data['author'] = str(author)	# 把裏面的名字轉換為id

        form = DetailModelForm(data=data)
        if form.is_valid():
            # 如歌数据合法,保存到数据库
            # print(form.cleaned_data)
            form.save()

            return redirect('/index/')
        else:
            # 校验失败
            # print(form.errors)
            return render(request, 'detail_add.html', {'form': form})

報錯

理論上感覺沒錯了,但是運行還是報以下錯

 AttributeError: This QueryDict instance is immutable

問題分析

因为默认的 QueryDict 是不可修改的。解决办法就是复制一份副本,对副本进行修改

解決方案

request.POST = request.POST.copy()

view.py修改版本:

class AddView(View):
    """ 添加用戶詳情 """

    def get(self, request):
        form = DetailModelForm()
        return render(request, 'detail_add.html', {'form': form})

    def post(self, request):
        # 用户POST提交数据,数据校验
        # 修改版本
        author = request.POST.get('author')	# 得到表單中author
        author = Author.objects.get(author=author).pk	# 得到該人的id,pk是主鍵的意思這裏用 .id 也是一樣
        request.POST = request.POST.copy()
        data = request.POST
        data['author'] = str(author)	# 把裏面的名字轉換為id

        form = DetailModelForm(data=data)
        if form.is_valid():
            # 如歌数据合法,保存到数据库
            # print(form.cleaned_data)
            form.save()

            return redirect('/index/')
        else:
            # 校验失败
            # print(form.errors)
            return render(request, 'detail_add.html', {'form': form})

報錯

如果輸入一個數據庫不存在的名字,那麽Author.objects.get(author=author).pk會報錯

raise self.model.DoesNotExist(

解決方案

try…except

        try:
            author = Author.objects.get(author=author).pk
            data['author'] = str(author)
            form = DetailModelForm(data=data)
        except Author.DoesNotExist:
            form = DetailModelForm(data=data)
            # form.add_error('author', '作者不存在')
            form.errors.get('author')[0] = '作者不存在'

view.py最終版本:

class AddView(View):
    """ 添加用戶詳情 """

    def get(self, request):
        form = DetailModelForm()
        return render(request, 'detail_add.html', {'form': form})

    def post(self, request):
        # 用户POST提交数据,数据校验
        # 最終版本
        request.POST = request.POST.copy()
        data = request.POST
        author = request.POST.get('author')
        try:
            author = Author.objects.get(author=author).pk
            data['author'] = str(author)
            form = DetailModelForm(data=data)
        except Author.DoesNotExist:
            form = DetailModelForm(data=data)
            # form.add_error('author', '作者不存在')
            form.errors.get('author')[0] = '作者不存在'

        if form.is_valid():
            # 如歌数据合法,保存到数据库
            # print(form.cleaned_data)
            form.save()

            return redirect('/index/')
        else:
            # 校验失败
            # print(form.errors)
            return render(request, 'detail_add.html', {'form': form})

總結

這樣雖然成功解決,但是我感覺ModelForm應該本身就有解決這個問題的辦法,本來我想用鈎子函數去解決,但是form.is_valid()就是False了進不去鈎子函數。如果以後找到更好的辦法再修改該方案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/384286.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ERP的实施节省了公司人力吗?

业界一直有句老话&#xff1a;“不上ERP等死&#xff0c;上了ERP找死”。 可把ERP的尴尬处境说透了。 有人把ERP奉为信仰&#xff1a;“那些说ERP不好用的根本是没用明白。” 有人则认为ERP只是卖概念&#xff0c;冷嘲&#xff1a;“实施ERP的企业&#xff0c;估计一半都倒闭…

手机质保调到36个月,会对行业造成怎样的冲击?

2月17日&#xff0c;中国信通院发布数据显示&#xff0c;2022年全年国内市场手机出货量累计2.72亿部&#xff0c;同比下降22.6%。其中5G手机的出货量为2.14亿部&#xff0c;同比下降19.6%。这则数据打破了一些手机行业内的美好幻想&#xff1a;5G时代的到来&#xff0c;并没有涌…

哔哩哔哩自动生成视频上传,B站发布软件使用教程

哔哩哔哩自动生成视频上传&#xff0c;B站发布软件使用教程&#xff0c;全自动引流发帖软件介绍#引流发帖软件#全自动引流发帖#引流推广#拓客引流#爆粉软件 大家好&#xff0c;我是百收编辑狂潮老师&#xff0c;下面给大家讲一下 b 站上传软件它的一个使用方法。第一次使用的时…

几种常见的 JVM 调优场景

一、cpu占用过高 cpu占用过高要分情况讨论&#xff0c;是不是业务上在搞活动&#xff0c;突然有大批的流量进来&#xff0c;而且活动结束后cpu占用率就下降了&#xff0c;如果是这种情况其实可以不用太关心&#xff0c;因为请求越多&#xff0c;需要处理的线程数越多&#xff…

[Java·算法·困难]LeetCode25. K 个一组翻转链表

每天一题&#xff0c;防止痴呆题目示例分析思路1题解1分析思路2题解2分析思路3题解3&#x1f449;️ 力扣原文 题目 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。…

JavaWeb--用户注册登录案例

用户注册登录案例1 用户登录1.1 需求分析1.2 环境准备1.3 代码实现2 用户注册2.1 需求分析2.2 代码编写3 SqlSessionFactory工具类抽取目标&#xff1a; 能够完成用户登录注册案例的实现能够完成SqlSessionFactory工具类的抽取 接下来我们通过两个比较常见的案例&#xff0c;一…

国家能源局持续发文,赛宁网安以实力响应电力网络靶场建设

​​一、政策导向 ​​国家能源局连续三年发文 推进电力网络靶场建设 2021.1. 国家能源局印发《2021电力安全监管重点工作任务》提出&#xff1a;加强电网及网络安全监管。推进电力行业网络安全仿真验证环境&#xff08;靶场&#xff09;建设&#xff0c;组织开展电力行业网…

如何构建一个稳定、可靠、安全的大型工业机械远程监控系统?

在工业机械设备的应用过程中&#xff0c;对于生产的质量、效率等要求都非常高&#xff0c;尤其是大型设备往往需要多人协同操作&#xff0c;如果没有实时的数据反馈和监控系统进行数据处理&#xff0c;就会出现数据偏差甚至错误现象。当前&#xff0c;国内大型工业机械设备数量…

AB测试-A/B Test

网络上有很多类似名称&#xff0c;又名A/B试验&#xff0c;ab test。 文章目录一、应用场景二、什么是AB测试三、AB测试可以解决什么问题四、AB测试的流程五、AB测试常见的误区六、AB测试的原理一、应用场景 以公司遇到的问题及需求入手&#xff0c;帮助大家建立感性认识。总结…

动态规划:leetcode 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

leetcode 198.打家劫舍leetcode 213.打家劫舍IIleetcode 337.打家劫舍IIIleetcode 198.打家劫舍你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相…

GitCode使用教程

目录 0.前言 1. 安装git 2. 注册 gitcode 3. 创建SSH key 4. GitCode 中配置公钥 5. 新建项目 6. clone项目 7. push 项目 0.前言 笔者之前大致知道&#xff0c;2020年9月10日&#xff0c;CSDN正式推出全新升级的开源平台 GitCode&#xff0c;不过鉴于稳定性原因一直没…

第十章 优化stop功能

优化stop功能 突然发现其实stop存在边缘案例是没有通过的&#xff0c;比如我图中红框中的obj.prop 当加上这句代码后&#xff0c;运行测试案例是不能通过的&#xff0c;原因分析&#xff1a; stop后已经把依赖清除了&#xff0c;obj.prop又走了get&#xff0c;触发了依赖收集…

Java 获取文件后缀名【一文总结所有方法】

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Delphi 中 FireDAC 数据库连接(管理事务)

参见&#xff1a;Delphi 中 FireDAC 数据库连接&#xff08;总览&#xff09;描述了如何使用FireDAC来管理DBMS事务。FireDAC提供TFDConnection和TFDTransaction组件来帮助你处理数据库事务。一、概述默认情况下&#xff0c;FireDAC应用程序在自动提交模式下工作&#xff0c;当…

Spring Cloud Alibaba全家桶(四)——微服务调用组件Feign

前言 本文小新为大家带来 微服务调用组件Feign 的相关知识&#xff0c;具体内容包含什么是Feign&#xff0c;Spring Cloud Alibaba快速整合OpenFeign&#xff0c;Spring Cloud Feign的自定义配置及使用&#xff08;包括&#xff1a;日志配置、契约配置、自定义拦截器实现认证逻…

五方面提高销售流程管理的CRM系统

销售充满了不确定性&#xff0c;面对不同的客户&#xff0c;销售人员需要采用不同的销售策略。也正因为这种不确定性&#xff0c;规范的销售流程对企业尤为重要&#xff0c;它会让销售工作更加有效&#xff0c;快速地实现成交。下面小编给您推荐个不错的CRM销售流程管理系统。 …

BQ25071QWDQCRQ1示意图ISO6721BQDRQ1引脚配置ISO7330CQDWRQ1数字隔离器

1、BQ25071QWDQCRQ1应用程序示意图BQ25071 1A 单输入、单节线性电池充电器是一款高度集成的线性 LiFePO4 电池充电器&#xff0c;适用于空间受限的便携式应用。它接受来自 USB 端口或交流适配器的电力&#xff0c;为单节 LiFePO4 电池提供高达 1A 的充电电流。该器件具有单个电…

【DaVinci Developer专题】-45-自动生成SWC中所有Runnable对应的C文件

点击返回「Autosar从入门到精通-实战篇」总目录 案例背景(共5页精讲): 在DaVinci Developer中,以Test_A_SWC的Runnable为例,见图0-1。我们现在尝试自动生成一个包含Test_A_SWC_Init和Test_A_SWC_Main函数原型(也是适用于 C/S Port Serve Runnable)的C文件。 图0-1 目…

详解旨在提升EVM底层性能的兼容公链Monad

EVM带来的繁荣2020年以太坊链上DeFi的蓬勃发展使得EVM成为关注焦点&#xff0c;大部分DeFi项目都开始基于以太坊公链&#xff0c;这也使得EVM成为行业的标杆&#xff0c;不少链都加入了EVM大军&#xff0c;比如polygon、BSC、fantom等等&#xff0c;而EVM也使得链上生态进一步繁…

【算法笔记】队列与优先队列

队列与优先队列 1.队列的概念 只允许在一端插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff1b;进行插入操作的一端称为队尾&#xff08;入队列&#xff09;&#xff0c;进行删除操作的一端称为队头&#xff08;出队列&#xff09;&#xff1b; 队列…