【问题标题】:Django: Passing value from template to viewDjango:将值从模板传递到视图
【发布时间】:2015-07-07 09:39:01
【问题描述】:

我遇到过这种情况:

单击 html 提交按钮,我调用 views.stream_response,它“激活”views.stream_response_generator,它“激活”stream.py 并返回一个 StreamingHttpResponse,我看到了在/stream_response/m 每秒递增一个数字:

1
2
3
4
5
6
7
8  //e.g. my default max value for m

stream.py

from django.template import Context, Template
import time         


def streamx(m):
    lista = []
    x=0
    while len(lista) < m:      
        x = x + 1
        time.sleep(1)
        lista.append(x)
        yield "<div>%s</div>\n" % x  #prints on browser
        print(lista)     #print on eclipse
    return (x)

views.py

def stream_response(request):   // unified the three functions as suggested

if request.method == 'POST':
    form = InputNumeroForm(request.POST)
    if form.is_valid():
        m = request.POST.get('numb', 8)
        resp = StreamingHttpResponse(stream.streamx(m))
        return resp

forms.py

from django.db import models
from django import forms
from django.forms import ModelForm

class InputNumero(models.Model):
    m = models.IntegerField()


class  InputNumeroForm(forms.Form):    
    class Meta:
        models = InputNumero
        fields = ('m',)

urls.py

...
url(r'^homepage/provadata/$', views.provadata),    
url(r'^stream_response/$', views.stream_response, name='stream_response'),
...

主页/provadata.html

<form id="streamform" action="{% url 'stream_response' %}" method="POST">
  {% csrf_token %}
  {{form}}
  <input id="numb" type="number"  />
  <input type="submit" value="to view" id="streambutton" />
</form>

如果我删除“8”并只使用m = request.POST.get('numb'),我会得到:

ValueError at /stream_response/ 视图 homepage.views.stream_response 没有返回 HttpResponse 对象。 而是返回 None。

所以,如果我尝试提交,它只需要默认值 8(并且有效),但它不需要我的表单输入。怎么了?

-->更新:@Tanguy Serrat 建议:

views.py

def stream_response(request):
    form = InputNumeroForm()
    if request.method == 'POST':
        form = InputNumeroForm(data=request.POST)
        if form.is_valid():
            #Accessing the data in cleaned_data
            m = form.cleaned_data['numero']

            print("My form html: %s" % form)      
            print ("My Number: %s" % m) #watch your command line
            print("m = ", m) 
            resp = StreamingHttpResponse(stream.streamx(m))
            return resp

    #If not post provide the form here in the template :
    return render(request, 'homepage/provadata.html', {'form': form,})

forms.py

class  InputNumeroForm(forms.Form):
    numero = models.IntegerField()

主页/provadata.py

<form  action="/stream_response/" method="POST">
    {% csrf_token %}
    {{form}}                                <!--issue: does not appear on the html !!!!!-->
    <input type="number" name="numero" />   <!--so I write this-->
    <input type="submit" value="to view" />
</form>

如果我提供输入,例如7 来自键盘:

/stream_response/ 处的 KeyError

'数字'

同时

如果我写m = request.POST.get('numero'),在命令行中我有:

...
My form html: 
My Number: 7
m =  7
...
   while len(lista) < m:
   TypeError: unorderable types: int() < str()

【问题讨论】:

  • 只是好奇为什么这一切不集中在一个函数中?另外,stream_response_generator_bis() 是在哪里定义的?
  • 抱歉复制粘贴时出错!没有 _bis 的 stream_response_generator()!我使用了几个函数,因为它对我来说更具可读性和可控性......我不知道如何做一个“一体化”类型的函数。
  • 上面的视图是否与当前给您错误的视图相同?看起来不像。
  • 不,它指的是建议。好的,我更新了视图,你是对的,谢谢。

标签: django django-forms django-views streaming httpresponse


【解决方案1】:

编辑: ModelForm 部分已移除,无需将数据保存在 DB 中,因此以这种方式使用经典表单:

方法一:使用Django的没有模型的经典表单

在您的 forms.py

中
from django import forms

class InputNumeroForm(forms.Form):

    numero = forms.IntegerField()

在您的 views.py

中
from django.shortcuts import render

def stream_response(request):
    form = InputNumeroForm()
    if request.method == 'POST':
        form = InputNumeroForm(data=request.POST)
        if form.is_valid():
            #Accessing the data in cleaned_data
            m = form.cleaned_data['numero']      
            print "My Number %s" % m #watch your command line 
            resp = StreamingHttpResponse(stream.streamx(m))
            return resp

    #If not post provide the form here in the template :
    return render(request, 'homepage/provadata.html', {
        'form': form,
    })

在您的模板中:

<form id="streamform" action="{% url 'stream_response' %}" method="POST">
  {% csrf_token %}
  {{ form }}
  <input type="submit" value="to view" id="streambutton" />
</form>

为了澄清一点,Django 中有两种类型的表单:

  • 不需要保存在数据库中的经典表单
  • Model Forms 这将允许您创建基于数据库模型的表单,即(您可以向您的数据库添加一行或编辑一个)

在这里,您无需将号码保存在数据库中,因此您可以使用经典形式: https://docs.djangoproject.com/en/1.8/topics/forms/

方法二: 不使用 Django 表单 对于像您的案例这样非常简单的表格:

在 views.py

from django.shortcuts import render

def stream_response(request):
    if request.method == 'POST':
        if request.POST.get('numero', False):
            m = int(request.POST['numero'])      
            print "My Number %s" % m #watch your command line 
            resp = StreamingHttpResponse(stream.streamx(m))
            return resp

    return render(request, 'homepage/provadata.html')

在您的模板中:

<form id="streamform" action="{% url 'stream_response' %}" method="POST">
  {% csrf_token %}
  <input type="number" name="numero" />
  <input type="submit" value="to view" id="streambutton" />
</form>

【讨论】:

  • 是的,我不想保存 InputNumeroForm 的值...我知道这可能看起来很奇怪,但我正在研究一些 Django 的东西,我很有兴趣了解它们是如何工作的。现在我试试你的建议。
  • 哦,好吧!我将编辑我的答案,为您提供经典的表单解决方案。顺便说一句:定义模型时,请确保在 models.py 而不是 forms.py 中声明它们
  • 感谢您对 Forms 和 ModelForms 的澄清。我观察到 print 需要括号 () (我正在使用 Python 3.4)但这不是问题.. 虽然我不明白 m = form.cleaned_data['numero'].. . 我必须在哪里定义 'numero' ?它给了我 KeyError at /stream_response/。最后,必须输入 ** 否则我无法输入任何数字作为输入“m”。
  • 对不起,我在 2.7!没有 Django 会为您处理 html 输入,当您定义:numero = forms.IntegerField() 并在您的 html 中添加 {{ form }} 时,它将使用name="numero" 创建一个输入您确定将表单传递给您的模板吗?试试打印这个print("my form %s" % form.cleaned_data.__dict__) 和print("My form html: %s" % form) 你会看到django是如何构建你的表单的
  • KeyError 是正常的,因为表单没有在您的模板上呈现。确保你在用return render(request, 'homepage/provadata.html', { 'form': form, }) 做我在views.py 中给你的。如果你不能做到这一点,你可以添加这个:&lt;input type="number" name="numero" /&gt; 但这不会帮助你弄清楚为什么你不能渲染 {{ form }}
【解决方案2】:

我发现您发布的代码存在一些问题:

您的表单字段缺少“名称”属性,因此为该字段设置的值不会传递给您的代码。这就是为什么您的 request.POST.get('numb') 返回 None 的原因,除非您提供默认值 (8)。 试试这个:

<input id="numb" name="numb" type="number"  />

另外,我注意到您在表单中使用了models.IntegerField - 您为什么要在这里使用模型字段?

对您来说更好的方法可能是将 numb 字段添加到表单中,然后从表单的已清理数据中检索值:form.cleaned_data['numb'] 而不是 POST 数据。

希望这能让你继续前进。

【讨论】:

  • 添加&lt;... name="numb" ... /&gt; 也不能使用默认值...name=" " 和id= " " 有什么区别?好的,我更改了表单定义...但我不知道为什么它适用于 models.IntegerField 而不适用于 forms.IntegerField。
【解决方案3】:

Django 视图必须返回一个 HttpResponse 对象。考虑到您引用的其他两个函数各只有一行,最好将所有内容放在一个函数中,或者至少将 StreamingHttpResponse 移至主函数。

编辑:StreamingResponseHttp 必须被赋予一个可迭代的,所以,回到 stream.py,尝试取出 return 和 print 函数(为了实验,我已经取出了多余的东西)。这在 shell 中对我有用。

def streamx(m):
    lista = []
    x=0
    while len(lista) < m:      
        x = x + 1
        time.sleep(1)
        lista.append(x)
        yield "<div>%s</div>\n" % x  #prints on browser

        #c = Context({'x': x})
        #yield Template('{{ x }} <br />\n').render(c)  


def stream_response(request):

    if request.method == 'POST':
        form = InputNumeroForm(request.POST)
        if form.is_valid():
            m = request['numb']

            resp = StreamingHttpResponse(streamx(m))
            return resp

【讨论】:

  • 我试过了,它返回:TypeError at /stream_response/ 'WSGIRequest' object is not callable
  • 抱歉,我不明白这样写是怎么工作的;需要初始化lista = [ ](“lista”对应英文“list”),放入lista.append(x)添加值,还需要返回一些东西(return (x) ),不是吗?我是编程新手,也许“我正在失去一些东西”:-/。
  • 你说得对,我正在查看我在 shell 中运行的示例。我把列表加回来了。
猜你喜欢
  • 2018-02-10
  • 2021-02-03
  • 2020-06-08
  • 2015-09-18
  • 2013-07-29
  • 1970-01-01
  • 2017-04-26
  • 2016-09-28
  • 2020-03-19
相关资源
最近更新 更多