动态将字段添加为表单

如何解决动态将字段添加为表单

| 我的表格中有3个字段。 我有一个提交按钮和一个“添加其他字段”按钮。 我知道我可以在表单类中使用
__init__
方法添加字段。 我是Python和Django的新手,并且遇到了一个新手问题;我的问题是: 当我单击“添加其他字段”按钮时,添加其他字段的过程是什么? 是否需要再次呈现表单? 如何以及何时调用
__init__
,甚至必须调用它? 如何将参数传递给
__init__
?     

解决方法

您的表单必须基于从POST传递给它的一些变量来构造(或盲目检查属性)。每次重新加载视图时(无论是否加载)都会构造表单本身,因此HTML需要包含有关构造正确数量的字段以进行验证的字段数量的信息。 我将以3的工作方式来研究这个问题:存在一个隐藏字段,其中包含活动表单的数量,每个表单名称前都带有表单索引。 实际上,您可以将一个字段
FormSet
https://docs.djangoproject.com/en/dev/topics/forms/formsets/#formsets 如果您不想使用
FormSet
,则可以随时创建此行为。 这是从头开始制作的-它应该给您一些想法。它还回答了有关将参数传递给
__init__
的问题-您只需将参数传递给对象构造函数:
MyForm(\'arg1\',\'arg2\',kwarg1=\'keyword arg\')
形式
class MyForm(forms.Form):
    original_field = forms.CharField()
    extra_field_count = forms.CharField(widget=forms.HiddenInput())

    def __init__(self,*args,**kwargs):
        extra_fields = kwargs.pop(\'extra\',0)

        super(MyForm,self).__init__(*args,**kwargs)
        self.fields[\'extra_field_count\'].initial = extra_fields

        for index in range(int(extra_fields)):
            # generate extra fields in the number specified via extra_fields
            self.fields[\'extra_field_{index}\'.format(index=index)] = \\
                forms.CharField()
视图
def myview(request):
    if request.method == \'POST\':
        form = MyForm(request.POST,extra=request.POST.get(\'extra_field_count\'))
        if form.is_valid():
            print \"valid!\"
    else:
        form = MyForm()
    return render(request,\"template\",{ \'form\': form })
的HTML
<form>
    <div id=\"forms\">
        {{ form.as_p }}
    </div>
    <button id=\"add-another\">add another</button>
    <input type=\"submit\" />
</form>
JS
<script>
let form_count = Number($(\"[name=extra_field_count]\").val());
// get extra form count so we know what index to use for the next item.

$(\"#add-another\").click(function() {
    form_count ++;

    let element = $(\'<input type=\"text\"/>\');
    element.attr(\'name\',\'extra_field_\' + form_count);
    $(\"#forms\").append(element);
    // build element and append it to our forms container

    $(\"[name=extra_field_count]\").val(form_count);
    // increment form count so our view knows to populate 
    // that many fields for validation
})
</script>
    ,我曾经不得不动态创建带有动态字段的表单。我用这个技巧做到了:
from django import forms

...

dyn_form = type(\'DynForm\',# form name is irrelevant
                (forms.BaseForm,),{\'base_fields\': fields})
请参阅此链接以获取更多信息: 动态表格 但是除此之外,我还必须注入字段,即在创建表单类后将其动态添加到表单类中。
dyn_form.base_fields[\'field1\'] = forms.IntegerField(widget=forms.HiddenInput(),initial=field1_val)
dyn_form.base_fields[\'field2\'] = forms.CharField(widget=forms.HiddenInput(),initial=field2_val)
那行得通。     ,没有javascript和字段类型的方法不在js中描述: 蟒蛇
 def __init__(self,**kwargs):
        super(Form,**kwargs)

        ##ajouts des champs pour chaque chien
        for index in range(int(nb_dogs)):
            self.fields.update({
                \'dog_%s_name\' % index: forms.CharField(label=_(\'Name\'),required=False,max_length=512),})

 def fields_dogs(self):
        fields = []
        for index in range(int(nb_dogs)):
            fields.append({
                \'name\': self[\'dog_%s_name\' % index],})
        return fields
模板
{% for field_dog in f.fields_dogs %}
        <thead>
            <tr>
                <th style=\"background-color: #fff; border-width: 0px;\"></th>
                <th>{% trans \'Dog\' %} #{{forloop.counter}}</th>
                <th>{% trans \'Name\' %}</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td style=\"background-color: #fff; border-width: 0px;\"></td>
                <td style=\"background-color: #fff; border-width: 0px;\"></td>
                <td>{{field_dog.name.errors}}{{field_dog.name}}</td>
            </tr>
            <tr>
                <td style=\"padding: 10px; border-width: 0px;\"></td>
            </tr>
        </tbody>
{% endfor %}
    ,该答案基于@Yuji \'Tomita \'Tomita的改进和更改。 尽管@Yuji \'Tomita \'Tomita的答案很好,并且很好地说明了构建“以django格式添加额外字段”功能所遵循的方向,但我发现其中的某些部分存在一些问题代码。 在这里,我根据@Yuji \'Tomita \'Tomita的最初建议提供工作代码: 视图(在view.py文件中) 视图中并没有真正改变:
def myview(request):

  if request.method == \'POST\':

    form = MyForm(request.POST,extra=request.POST.get(\'total_input_fields\'))

      if form.is_valid():
        print \"valid!\"
      else:
        form = MyForm()
return render(request,{ \'form\': form })
表格(在form.py文件中)
class MyForm(forms.Form):

    empty_layer_name = forms.CharField(max_length=255,required=True,label=\"Name of new Layer\")

    total_input_fields = forms.CharField(widget=forms.HiddenInput())


    def __init__(self,**kwargs):

      extra_fields = kwargs.pop(\'extra\',0)

      # check if extra_fields exist. If they don\'t exist assign 0 to them
      if not extra_fields:
         extra_fields = 0

      super(MyForm,**kwargs)
      self.fields[\'total_input_fields\'].initial = extra_fields

      for index in range(int(extra_fields)):
        # generate extra fields in the number specified via extra_fields
        self.fields[\'extra_field_{index}\'.format(index=index)] = forms.CharField()
模板HTML
<form id=\"empty-layer-uploader\" method=\"post\" enctype=\"multipart/form-data\" action=\"{% url \"layer_create\" %}\">
        <div id=\"form_empty_layer\">
          <input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"{{ csrf_token }}\">
            {{ form.errors }}
            {{ form.non_field_errors }}
            {% if errormsgs %}
              {% for value in errormsgs %}
                </p>  {{ value }} </p>
              {% endfor %}
            {% endif %}
            {% for error in form_empty_layer.non_field_errors %}
              {{ error }} </br>
            {% endfor %}
            </br>
            {% for field in form_empty_layer.visible_fields %}
              {{ field }} </br>
            {% endfor %}
        </div>
        </br>
        <button type=\"button\" id=\"add-another\">add another</button> </br> </br>
        <button type=\"submit\" id=\"empty-layer-button\" name=\"emptylayerbtn\">Upload</button>
        </br></br>
        // used in order to save the number of added fields (this number will pass to forms.py through the view)
        <input type=\"text\" name=\"total_input_fields\"/>
</form>
模板jQuery
// check how many times elements with this name attribute exist: extra_field_*
form_count = $(\'input[name*=\"extra_field_*\"]\').length;

// when the button \'add another\' is clicked then create a new input element
$(document.body).on(\"click\",\"#add-another\",function(e) {
  new_attribute = $(\'<input type=\"text\"/>\');
  // add a name attribute with a corresponding number (form_count)
  new_attribute.attr(\'name\',\'extra_field_\' + form_count);
  // append the new element in your html
  $(\"#form_empty_layer\").append(new_attribute);
  // increment the form_count variable
  form_count ++;
  // save the form_count to another input element (you can set this to invisible. This is what you will pass to the form in order to create the django form fields
  $(\"[name=total_input_fields]\").val(form_count);

})
    ,Yuji \'Tomita \'Tomita \的解决方案是您能找到的最好的解决方案,但是假设您有一个多步骤表单,并且使用django-formtools应用程序,则将需要解决一些问题。谢谢Yuji \'Tomita \'Tomita,您对我有很大帮助:) 表格
class LicmodelForm1(forms.Form):
     othercolumsvalue = forms.IntegerField(min_value=0,initial=0)
class LicmodelForm2(forms.Form):
    def __init__(self,**kwargs):
    extra_fields = kwargs.pop(\'extra\',0)

    super(LicmodelForm2,**kwargs)

    for index in range(int(extra_fields)):
        # generate extra fields in the number specified via extra_fields
        self.fields[\'othercolums_{index}\'.format(index=index)] = \\
            forms.CharField()
        self.fields[\'othercolums_{index}_nullable\'.format(index=index)] = \\
            forms.BooleanField(required=False)
对于多步骤表单,您将不需要多余的字段,在此代码中,我们在第一步中使用othercolumsvalue字段。 views.py
class MyFormTool(SessionWizardView):
def get_template_names(self):
    return [TEMPLATES[self.steps.current]]

def get_context_data(self,form,**kwargs):
    context = super(MyFormTool,self).get_context_data(form=form,**kwargs)
    data_step1 = self.get_cleaned_data_for_step(\'step1\')
    if self.steps.current == \'step2\':

        #prepare tableparts for the needLists
        needList_counter = 0
        for i in self.wellKnownColums:
            if data_step1[i] is True:
                needList_counter = needList_counter + 1
                pass

        #prepare tableparts for othercolums
        othercolums_count = []
        for i in range(0,data_step1[\'othercolumsvalue\']):
            othercolums_count.append(str(i))

        context.update({\'step1\': data_step1})
        context.update({\'othercolums_count\': othercolums_count})

    return context

def get_form(self,step=None,data=None,files=None):
    form = super(MyFormTool,self).get_form(step,data,files)

    if step is None:
        step = self.steps.current

    if step == \'step2\':
        data = self.get_cleaned_data_for_step(\'step1\')
        if data[\'othercolumsvalue\'] is not 0:
            form = LicmodelForm2(self.request.POST,extra=data[\'othercolumsvalue\'])
    return form

def done(self,form_list,**kwargs):
    print(\'done\')
    return render(self.request,\'formtools_done.html\',{
        \'form_data\' : [form.cleaned_data for form in form_list],})
通过覆盖get_form()和get_context_data()函数,您可以在呈现表单之前覆盖它。模板文件也不再需要JavaScript:
            {% if step1.othercolumsvalue > 0 %}
            <tr>
                <th>Checkbox</th>
                <th>Columname</th>
            </tr>
            {% for i in othercolums_count %}
                <tr>
                    <td><center><input type=\"checkbox\" name=\"othercolums_{{ i }}_nullable\" id=\"id_othercolums_{{ i }}_nullable\" /></center></td>
                    <td><center><input type=\"text\" name=\"othercolums_{{ i }}\" required id=\"id_othercolums_{{ i }}\" /></center></td>
                </tr>
            {% endfor %}
        {% endif %}
由于名称相同,也从formtools重新验证了动态创建的step2中的字段。但是要到达那里,您将必须解决for-each模板循环,如下所示: 从get_context_data()函数
        othercolums_count = []
        for i in range(0,data_step1[\'othercolumsvalue\']):
            othercolums_count.append(str(i))
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-