Django: Passing value from template to view

荒凉一梦 提交于 2019-12-30 03:34:08

问题


I HAD this situation:

Clicking on a html submit button, I call views.stream_response which "activates" views.stream_response_generator which "activates" stream.py and return a StreamingHttpResponse and I see a progressive number every second up to m at /stream_response/:

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'),
...

homepage/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>

If I delete "8" and use only m = request.POST.get('numb') I obtain:

ValueError at /stream_response/ The view homepage.views.stream_response didn't return an HttpResponse object. It returned None instead.

So, if I try to submit, it takes only the default value 8 (and works) but it not takes my form input. What is it wrong?

-->UPDATE: with @Tanguy Serrat suggestions:

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()

homepage/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>

If I give as input e.g. 7 from keyboard:

KeyError at /stream_response/

'numero'

WHILE

If I write m = request.POST.get('numero'), in command line I have:

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

回答1:


EDIT : ModelForm part removed, no need to save the data in DB so using classic form this way :

Method 1 : Classic Form without Model using Django

in your forms.py

from django import forms

class InputNumeroForm(forms.Form):

    numero = forms.IntegerField()

in your 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,
    })

in your template :

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

To clarify a little there are two types of form in Django :

  • Classic Forms which do not require saving in a database
  • Model Forms which will allow you to create forms which are based on a Database Model i.e. (you can add a row to your db or edit one)

Here you don't need to save your number in your database so you use classical forms: https://docs.djangoproject.com/en/1.8/topics/forms/

Method 2 : Not using the Django Form For very simple forms like your case :

in 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')

in your template :

<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>



回答2:


I see a handful of issues with the code you posted:

Your form field is missing the 'name' attribute, and thus the value set for this field will not be passed to your code. This is why your request.POST.get('numb') returns None unless you provide your default (8). Try this:

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

Also, I noticed in your form you use models.IntegerField - why are you trying to use a model field here?

A better approach for you may be to add the numb field to your form and then retrieve the value from the form's cleaned data: form.cleaned_data['numb'] instead of the POST data.

Hopefully this gets you going.




回答3:


Django views MUST return a HttpResponse object. Considering that the other two functions you're referencing have only one line each, it would serve you better to just put everything in one function, or at least move the StreamingHttpResponse to the main function.

Edit: The StreamingResponseHttp must be given an iterable so, going back to the stream.py, try taking out the return and print functions (I've taken out excess stuff for experimentation's sake). This worked for me in the 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


来源:https://stackoverflow.com/questions/29921085/django-passing-value-from-template-to-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!