如何根据用户输入动态更改 django 中的表单(提交前)

Posted

技术标签:

【中文标题】如何根据用户输入动态更改 django 中的表单(提交前)【英文标题】:How to dynamically change a form in django based on user input (before submission) 【发布时间】:2020-12-05 18:36:13 【问题描述】:

我正在做一个网页,其中包含一个必须根据之前的用户输入(在提交之前)动态更改的表单。例如,如果名称以字符串S.L 结尾,则需要自动跨越其余字段以引入公司数据,否则必须使用默认值或任何值提交表单。

表单继承自模型,所有内容都呈现为酥脆的表单。

在 views.py 我有:

@login_required
def form_home(request):

    if request.method == 'POST':

        Inputs = InputsForm(request.POST)

        if Inputs.is_valid():

            inp = Inputs.save(commit=False)
            inp.author = request.user
            inp.email = request.user.email

            data = 'email': request.user.email, **Inputs.cleaned_data
            obtain_calculate_create_send(data)

            inp.save()
            messages.success(request, f'Your form is valid!')
            return redirect('result/' + str(inp.pk) + '/')
        else:
            messages.warning(request, f'Please, check the inputs and enter valid ones')

        content = 'Inputs': Inputs, 'title': 'valuations'

    else:
        Inputs = InputsForm(request.POST or None)
        content = 'Inputs': Inputs, 'title': 'valuations'

    return render(request, 'valuations/form_home.html', content)

在forms.py中:

class InputsForm(forms.ModelForm):
    # Basic Info 

    country_choices = import_lists('Countries', equal=True)
    years = import_lists('years')

    name = forms.CharField(label='Company Name', initial='Example. S.L')
    country = forms.TypedChoiceField(choices=country_choices, label='Country')
    foundation_year = forms.TypedChoiceField(coerce=int, choices=years, label='Foundation year')
    employees = forms.IntegerField(label='Number of employees')
    industry = forms.TypedChoiceField(choices=industry_choices, label='Industry')
    class Meta:
        model = Inputs
        exclude = ('author', 'email', 'date_inputs_created ')

在models.py中:

class Inputs(models.Model):

    def __str__(self):
        return f'self.author´s inputs for self.name created at self.date_inputs_created'

    # Useful information for the data base
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    date_inputs_created = models.DateTimeField(auto_now_add=True)
    email = models.EmailField(max_length=254, default='example@compani.com')

    # Actual inputs
    # Basic Info 
    # ---------
    country_choices = import_lists('Countries', equal=True)
    industry_choices = import_lists('Industry', equal=True)

    name = models.CharField(max_length=100)
    country = models.CharField(max_length=30, choices=country_choices, default='Germany')
    foundation_year = models.PositiveSmallIntegerField(choices=years)
    employees = models.PositiveIntegerField(default=20)
    industry = models.CharField(max_length=50, choices=industry_choices)

在 HTML 中:

% block content %
  <form method="post">
    % csrf_token %
     Inputs|crispy 
    <button type="submit" class="btn btn-primary">submit</button>
  </form>
% endblock %

感谢任何帮助,提前致谢。

【问题讨论】:

【参考方案1】:

为了让您了解如何改变它,我认为可以通过三种方式实现。

    使用 Django Signals 运行预保存函数,检查名称是否包含“S.L”并相应地应用字段逻辑。

    更改您的视图功能并在那里应用逻辑。

    劫持您的模型保存方法并检查名称是否包含“S.L”并在那里应用逻辑。

我会选择选项 3,因为它更简单、更快。举个例子,在 Inputs 模型定义中添加以下代码

def save(self, *args, **kwargs):
     name= self.name
     if name.endswith("S.L"):
         self.country = 'Company country'
         self.foundation_year = 'Company year'
    .... And so on ...........
     super().save(*args, **kwargs)

上述代码的工作原理是,对于每个传入的数据,它都会检查名称是否以“S.L”结尾并更改逻辑。

您可以更改视图逻辑并应用此条件,但如果您不想更改当前视图定义,也可以这样做。

如果你想尝试选项 2,那么,试试这个

if request.method == 'POST':

    Inputs = InputsForm(request.POST)

    if Inputs.is_valid():

        inp = Inputs.save(commit=False)
        inp.author = request.user
        inp.email = request.user.email

        # CODE -----------------------
        name = inp.name
        if name.endswith("S.L"):
           inp.country = 'Company country'
           inp.foundation_year = 'Company year'

          .... And so on ...........
        #CODE ! ----------------------             

        data = 'email': request.user.email, **Inputs.cleaned_data
        obtain_calculate_create_send(data)

        inp.save()
        messages.success(request, f'Your form is valid!')
        return redirect('result/' + str(inp.pk) + '/')
    else:
        messages.warning(request, f'Please, check the inputs and enter valid ones')

    content = 'Inputs': Inputs, 'title': 'valuations'

else:
    Inputs = InputsForm(request.POST or None)
    content = 'Inputs': Inputs, 'title': 'valuations'

return render(request, 'valuations/form_home.html', content)

【讨论】:

嗨,问题是,如果它提交的表单,这将起作用,但我需要的是显示给用户的字段会根据输入动态变化,而无需提交该输入。例如,您填写一个字段,然后出现新字段而不提交,然后您提交所有已填写的字段,其余字段显示为空值或默认值。

以上是关于如何根据用户输入动态更改 django 中的表单(提交前)的主要内容,如果未能解决你的问题,请参考以下文章

django——form组件

Django 中的动态表单要求

django - 动态添加 django 表单字段并保留用户输入

如何根据表单输入添加动态复选框?

如何根据复选框输入启用django表单字段?

动态计算输入值 - React