动态添加 Django 表单集实例并使用 HTMX POST 的正确方法是什么?

2023-12-12

我正在制作一个表格嵌套动态表单集 using htmx我(想逃避使用JS,但如果没有选择......)实例更多表单集字段为了使动态嵌套形式,但是当我POST,仅数据来自1 个实例 of the Chlid formset (最后一个)已发布,表单的其余部分正确发布,并且Child model得到与Parent model

我阅读了 django 文档,了解如何POST 表单集实例并尝试将其应用到我的代码中,我也知道了如何发布两者 Parent and Child同时。对于表单集,我正在发出 htmx get 请求hx-get对于包含子表单集并且效果很好的部分模板,唯一的问题是这总是返回一个form-0formset 到客户端,所以对于POST数据重复x每个字段的时间,并且只获取最后一个实例中放置的数据,但是我尝试更改extra=int我的表单集上的值以使更多表单直立,这给出了预期的结果,一子实例执行表格extra=int,所以我的问题是htmx和我打电话的方式new Child formset实例。

这是我的代码。(我计划在这个表单中嵌套更多的子表单集,所以我称之为sformset为了方便)

****views.py****

def createPlan(request):#Requst for the Parent form 

    form = PlanForm(request.POST or None)
    sformset = StructureFormset(request.POST or None) #Nesting the Child formset

    context = {
        'form':form,
        'sformset':sformset,
        }

    if request.method == 'POST':

        print(request.POST)
        if form.is_valid() and sformset.is_valid():

            plan = form.save(commit=False)
            print(plan)
            plan.save()
             
            sform = sformset.save(commit=False)     
            for structure in sform:

                structure.plan = plan
                structure.save()

    return render(request, 'app/plan_forms.html', context)


def addStructure(request):

    sformset = StructureFormset(queryset=Structure.objects.none())#add a empty formset instance 
    
    context = {"sformset":sformset}

    return render(request, 'app/formsets/structure_form.html', context)
****forms.py****

StructureFormset = modelformset_factory(Structure,
        fields = (
            'material_type',
            'weight',
            'thickness',
            'provider'
        ))
****relevant part for plan_forms.html template****

<form method="POST">
  {% csrf_token %}
  <div class="col-12 px-2">
    <div class="row px-3 py-1">
      <div class="col-3 px-1">{{ form.format }}</div>
      <div class="col-3 px-1">{{ form.pc }}</div>
      <div class="col-3 px-1">{{ form.revission }}</div>
      <div class="col-3 px-1">{{ form.rev_date }}</div>
    </div>
    <div class="row px-3 py-1">
      <div class="col-3 px-1">{{ form.client }}</div>
      <div class="col-3 px-1">{{ form.product }}</div>
      <div class="col-3 px-1">{{ form.gp_code }}</div>
      <div class="col-3 px-1">{{ form.code }}</div>
    </div>
  </div>
  <div>
    <table>
      <tbody style="user-select: none;" id="structureforms" hx-sync="closest form:queue">
        <!--Structure formset goes here-->
      </tbody>
      <tfoot>
        <a href="" hx-get="{% url 'structure-form' %}" hx-swap="beforeend" hx-target="#structureforms">
          Add structure <!--Button to call structure formset-->
        </a>
      </tfoot>
    </table>
  </div>
  <div class="col-12 px-2">
    <div class="row px-4 py-1">{{ form.observation }}</div>
    <div class="row px-4 py-1">{{ form.continuation }}</div>
    <div class="row px-4 py-1">{{ form.dispatch_conditions }}</div>
    <div class="row px-3 py-1">
      <div class="col-6 px-1">{{ form.elaborator }}</div>
      <div class="col-6 px-1">{{ form.reviewer }}</div>
    </div>
  </div>
  <button type="submit">Submit</button>
</form>
****formsets/structure_form.html****

<tr>
  <td class="col-12 px-1">
    {{ sformset }}
  </td>
</tr>
**** relevant urls.py****

urlpatterns = [
    path('create_plan/', views.createPlan, name='create_plan'),
    path('htmx/structure-form/', views.addStructure, name='structure-form')]

另外,我内置的表格admin.py using fields and inlines正是我想要的原始产品(初始格式集和样式的数量除外)


总结一下问题:目前,您的代码成功引入了新的表单集,但是每个新的表单集都带有一个name的属性form-0-title(同上对于id和其他属性)。此外,添加新的表单集后hx-get最初创建的隐藏字段ManagementForm将不再反映页面上的表单集数量。

需要什么

将新的表单集添加到站点后,我认为需要执行以下操作,以便 Django 可以处理表单提交。

  1. 更新value输入元素中的属性id="id_form-TOTAL_FORMS"因此该数字与之后页面上的实际表单集数量相匹配hx-get引入新的表单集。

  2. 更新name and id新的表单集来自form-0-title使用反映当前表单集总数的任何数字。

  3. 更新标签'for属性以同样的方式。

您可以在客户端使用 Javascript 来完成此操作。或者,您可以在服务器端使用 Django 有效地执行相同的操作,然后 htmx 可以是完成其余操作所需的唯一 javascript。为此,我使用了empty_form创建可根据需要更改的表单集的 html 内容。该工作显示在build_new_formset()帮手,下。

Example

这是我正在做的工作:

forms.py

from django import forms
from django.forms import formset_factory

class BookForm(forms.Form):
    title = forms.CharField()
    author = forms.CharField()

BookFormSet = formset_factory(BookForm)

views.py

from django.utils.safestring import mark_safe
from app2.forms import BookFormSet


def formset_view(request):
    template = 'formset.html'

    if request.POST:
        formset = BookFormSet(request.POST)
        if formset.is_valid():
            print(f">>>> form is valid. Request.post is {request.POST}")
            return HttpResponseRedirect(reverse('app2:formset_view'))
    else:
        formset = BookFormSet()

    return render(request, template, {'formset': formset})


def add_formset(request, current_total_formsets):
    new_formset = build_new_formset(BookFormSet(), current_total_formsets)
    context = {
        'new_formset': new_formset,
        'new_total_formsets': current_total_formsets + 1,
    }
    return render(request, 'formset_partial.html', context)


# Helper to build the needed formset
def build_new_formset(formset, new_total_formsets):
    html = ""

    for form in formset.empty_form:
        html += form.label_tag().replace('__prefix__', str(new_total_formsets))
        html += str(form).replace('__prefix__', str(new_total_formsets))
    
    return mark_safe(html)

请注意:build_new_formset() helper: formset.empty_form将省略应该出现的索引号id, name and label属性,并将使用"__prefix__"。你想替换那个"__prefix__"部分与适当的数字。例如,如果它是页面上的第二个表单集id应该id_form-1-title(更改自id_form-__prefix__-title).

表单集.html

<form action="{% url 'app2:formset_view' %}" method="post">
  {% csrf_token %}
  {{ formset.management_form }}

  {% for form in formset %}
  <p>{{ form }}</p>    
  {% endfor %}

  <button type="button" 
          hx-trigger="click"
          hx-get="{% url 'app2:add_formset' formset.total_form_count %}"
          hx-swap="outerHTML">
    Add formset
  </button> 

  <input type="submit" value="Submit">
</form>

表单集_partial.html

<input hx-swap-oob="true" 
       type="hidden" 
       name="form-TOTAL_FORMS" 
       value="{{ new_total_formsets }}" 
       id="id_form-TOTAL_FORMS">

<p>{{ new_formset }}</p>

<button type="button" 
        hx-trigger="click"
        hx-get="{% url 'app2:add_formset' new_total_formsets %}"  
        hx-swap="outerHTML">
  Add formset
</button>

注意:隐藏的input:对于每个新添加的表单集,value of the input元素有id="id_form-TOTAL_FORMS"将不再反映页面上表单集的实际数量。您可以发送新的隐藏input与您的表单集并包括hx-swap-oob="true"在上面。然后 Htmx 将用新的替换旧的。

文档参考:https://docs.djangoproject.com/en/4.1/topics/forms/formsets/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态添加 Django 表单集实例并使用 HTMX POST 的正确方法是什么? 的相关文章

随机推荐

  • 如何缩放 SVG 图像以填充浏览器窗口?

    这看起来应该很容易 但我只是没有得到什么 我想要制作一个包含单个 SVG 图像的 HTML 页面 该图像会自动缩放以适合浏览器窗口 无需任何滚动 同时保留其纵横比 例如 目前我有一个 1024x768 SVG 图像 如果浏览器视口为 198
  • Google 在添加 Schema.org 标记时需要某些类型的某些属性吗?

    我尝试在我的网站上添加 Schema org 标记 类型为Article 然后在其上添加一些属性 当在Google结构化数据测试工具上检查时 它说需要某些属性 例如dataPublished author etc 我可以添加一些属性来满足要
  • 如何从 AngularJS 范围内的数组中删除项目?

    简单的待办事项列表 但列表页面上的每个项目都有一个删除按钮 相关模板 HTML tr td person name person id td td person description td td a href edit i class i
  • ASP.NET 5 Identity 3 用户在一段时间后注销

    我使用 RC1 位和外部 Google 身份验证 没有 Identity EntityFramework 在登录过程中 我设置了 记住我 标志 登录用户在浏览器重新启动 我看到 cookie 设置为 14 天后过期 和网站重新启动后仍然存在
  • 如何解决上下文中重新渲染过多的问题?

    每当我更新的时候user object in users array 在上下文中 所有使用的组件users重新渲染 我尝试过的 我有一个使用上下文中的值的组件 const DashboardCardList gt const context
  • MySQL - 从 PHP 插入日语 - 编码问题

    我正在尝试在 mysql 表中插入一些日语单词 如果我使用 phpMyAdmin 插入 则 phpMyAdmin 可以正常显示该单词 但如果我尝试通过 php 插入它 如下所示 mysql connect Host User Passwor
  • 使用xpath和java解析xml

    现在我想解析来自 webservice 的 xml 为了解析 我使用了xpath和java 我有以下代码 package test client import com sun org apache xpath internal NodeSe
  • 如何使用“api”或“implementation”指令从 gradle 插件获取依赖项

    背景 运行 Android Studio 3 0 beta7 并尝试获取一个适用于 Android 库的 javadoc 任务 事实上 这首先不能作为现成的任务提供 这真的很奇怪 我设法调整了一个根据我的需要回答不同的问题 最后得到这个代码
  • Pygame-创建更多 USEREVENT 类型事件的方法?

    这个问题是由于需要创建大量 USEREVENT 类型事件而产生的 由于我找不到有关如何创建超出限制的用户事件的信息 因此我来这里寻求帮助 目前我知道USEREVENT类型事件的值为24 最大允许的id为31 我还发现一些id s被保留 至少
  • 如何更改 Android Things 设备上的日期?

    我正在 Raspberry Pi 3 Model B 上使用 Android Things Developer Preview 有什么方法可以设置正确的日期 时间 时区 最简单的方法可能是使用date通过 ADB 执行 shell 命令 它
  • 检测何时按下标签栏项目

    我有一个根视图控制器 它没有设置为故事板上任何视图控制器的自定义类 相反 我的所有视图控制器都像这样子类化此类 RootViewController class RootViewController UIViewController UIT
  • Java中字符串结束符

    我正在解决一个简单的问题 在Java中删除字符数组中的某些字符 想法很简单 static void remove char char arr char c int r 0 for int i 0 i lt arr length i if a
  • 实时音频队列录音回放

    嘿伙计们 我正在尝试构建一个用于实时变声的应用程序 第一步 我设法将音频数据录制到指定文件并在录制后播放 现在我尝试更改在循环录制音频缓冲区后立即播放音频缓冲区的代码 我的问题是 如何直接从录音音频队列中读取音频数据 而不是 如文档中所示
  • 从 adb 获取包的可启动活动名称

    有没有办法从使用中获取包的可启动活动adb 对于未root的手机 即无需从中拉出apk data app目录并检查appt 我尝试了 dumpsys 但它不包含有关默认可启动活动的信息 Thanks 您不需要 root 即可从中提取 apk
  • 100% CPU 使用率下的 Java 线程优化

    我有一个应用程序 它接受队列上的工作 然后旋转该工作以在独立线程上完成 线程数量并不多 比如最多 100 个 但这些都是密集型任务 可以快速将 CPU 提升到 100 为了以最快的速度完成最多的工作 当我需要做更多的工作时 我最好只启动更多
  • 杀死在 Matlab 中创建的 Excel 进程

    鉴于我写入工作簿 目前我会终止所有 Excel 进程 以便我的代码在循环调用时可以正常工作 xlswrite path values system taskkill F IM EXCEL EXE 这使得我在处理另一个 Excel 文件时无法
  • Chrome Webstore 内联安装与 AngularJS

    我是 AngularJS 的新手 并尝试按照以下步骤安装 Chrome 扩展网上商店内联安装指南 在我的 html 文件中
  • 使用 Google Sheets API 和服务帐户时收到 403 禁止

    我有一个使用服务帐户的应用程序 因为它从 cron 作业运行 所以我无法让它通过浏览器中的用户进行授权 以下是我创建床单服务的方法 private static final String APPLICATION NAME my app pr
  • XStream 中的单元素数组错误

    如果你有这样的函数 List
  • 动态添加 Django 表单集实例并使用 HTMX POST 的正确方法是什么?

    我正在制作一个表格嵌套动态表单集 using htmx我 想逃避使用JS 但如果没有选择 实例更多表单集字段为了使动态嵌套形式 但是当我POST 仅数据来自1 个实例 of the Chlid formset 最后一个 已发布 表单的其余部