Determining if a simple_form object has been submitted yet - python

I am building a Form object using pyramid_simpleform. I would like to have one method that builds the form object and once submitted it attempts to validate it.
If the input valid, I'll redirect the user to a confirmation page. Otherwise, I'll render an error page. I am using form.validate() to see if the input data fits the schema.
If the form has not been submitted, I'd like to display the form using a render_to_response. How do I detect whether the form has been submitted?

Quick answer
Like Furbeenator answered:
if request.method == "POST":
Long answer
You should split your logic in two different view functions.
Also, you should return a form renderer to be used by your template instead of rendering the form straight in the view function. For example:
./forms.py:
from formencode import Schema, validators
class RegistrationForm(Schema):
email = validators.Email(not_empty=True, strip=True)
password = validators.UnicodeString(not_empty=True)
password_confirm = validators.UnicodeString()
chained_validators = [validators.FieldsMatch(
'password', 'password_confirm',
messages=dict(invalidNoMatch=u'Password does not match'))]
./views/accounts.py:
from pyramid_simpleform import Form
from pyramid_simpleform.renderers import FormRenderer
from pyramid.view import view_config
from pyramid.httpexceptions import HTTPFound
from pyramid.url import route_url
from ..forms import RegistrationForm
from ..models import DBSession, User
#view_config(route_name='accounts_register', renderer='/accounts/register.mako',
request_method='GET')
def register(request):
"""Shows the empty form."""
form = Form(request, schema=RegistrationForm)
return {'renderer': FormRenderer(form)}
#view_config(route_name='accounts_register', renderer='/accounts/register.mako',
request_method='POST')
def register_post(request):
"""Receives the posted form."""
form = Form(request, schema=RegistrationForm)
if form.validate():
user = User(form.data['email'], form.data['password'])
DBSession.add(user)
return HTTPFound(route_url('profile', request))
return {'renderer': FormRenderer(form)}
./templates/accounts/register.mako:
<form action="" method="post">
<div class="${' error' if renderer.is_error('email') else ''}">
<label for="email">Email</label>
${renderer.text('email', type='email', placeholder='Email')}
% if renderer.is_error('email'):
<span class="errors">${', '.join(renderer.errors_for('email'))}</span>
% endif
</div>
<!-- ... --->
</form>

If you have the request object, you can test it's method for "POST".
if request.method == "POST":

Related

Django : Form Successful but image not uploaded

MODELS.PY
class Campaign(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
campaign_image = models.ImageField(default="profilepic.jpg",upload_to="campaign_pictures")
FORMS.PY
class RaiseFundsFrom3(forms.ModelForm):
class Meta:
model = Campaign
fields = ['campaign_image']
VIEWS.PY
#login_required
def raise_funds_medical_3(request):
if request.method == 'POST':
form = RaiseFundsFrom3(request.POST, request.FILES or None, instance=request.user)
if form.is_valid():
check = form.save(commit=False)
check.save()
return HttpResponse('form worked')
else:
form = RaiseFundsFrom3()
return render(request,'funds/raise_funds_medical_3.html',{'form':form})
URLS.PY
path('raise/medical/photo', views.raise_funds_medical_3, name="raise_funds_medical_3"),
raise_funds_medical_3.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group pt-2">
<small>Photo formats must be PNG / JPG / JPEG</small>
<input type="file" name="campaign_image" />
</div>
<button class="btn btn-lg button_bfg_blue" type="submit"> <small><b> NEXT </b></small> </button>
</form>
on form submit, i do not get any error, but image is not uploaded to the required folder.
however, in the raise_funds_medical_3 function within views.py, if i remove instance=request.user, the image gets uploaded but i get following error : NOT NULL constraint failed: funds_campaign.user_id
Your form is a ModelForm for a Campaign, so its instance needs to be a Campaign. Don't assign request.user as its instance!
Now, your form isn't including the user field which is required to save a Campaign, so you should assign that yourself in the view before saving to the database:
campaign = form.save(commit=False) # this gives your the form's instance
campaign.user = request.user # this assigns the user
campaign.save() # this commits to the database
Also you should handle the case where the form isn't valid. This is quite simple, just un-indent the last return in your view function, so that return render(...) is also called in case the form isn't valid.
Finally, instead of returning a response when the form is valid, it's good practice to redirect to another view. This way, when the user refreshes the page, the form isn't submitted again. Your final code should look like this:
#login_required
def raise_funds_medical_3(request):
if request.method == 'POST':
form = RaiseFundsFrom3(request.POST, request.FILES or None)
if form.is_valid():
check = form.save(commit=False)
check.user = request.user
check.save()
return redirect(<url_pattern>)
else:
form = RaiseFundsFrom3()
return render(request,'funds/raise_funds_medical_3.html',{'form':form})
Supplementary answer to dirkgroten's one
I have come to completely hate the conventional structuring of a Django Function-based View. They can be re-factored by inverting the validity test and adding one line so that one and only one instantiation of a form is present. The result is IMO far easier to read, and easily generalizes for a view displaying two or more forms.
def raise_funds_medical_3(request):
args = [request.POST, request.FILES or None] if request.method == "POST" else []
form = RaiseFundsFrom3(*args)
if request.method != "POST" or not form.is_valid():
# unbound form or form not valid
return render(request,'funds/raise_funds_medical_3.html',{'form':form})
# form is valid so do the processing and redirect
check = form.save(commit=False)
check.user = request.user
check.save()
return redirect(<url_pattern>)
If you want to process >1 form, the test becomes
if request.method != "POST" or any(
[ not form.is_valid(), not form2.is_valid(), ...]):
which forces evaluation of .is_valid() for all forms, even if the first was not valid, so that all the error messages are shown to the user.
In a complex business application, the processing of a successful form submission may be quite a few more lines of code than this simple example. Having it at the end, not indented, isolated from all the boilerplate save the return redirect(...), makes things much easier!

I want something to be executed through django

I know this question was asked before, but none worked for me. I have this code that I want it to be executed when a button is clicked and a message is passed
import time
from sinchsms import SinchSMS
number = '+yourmobilenumber'
message = 'I love SMS!'
client = SinchSMS(your_app_key, your_app_secret)
print("Sending '%s' to %s" % (message, number))
response = client.send_message(number, message)
message_id = response['messageId']
response = client.check_status(message_id)
while response['status'] != 'Successful':
print(response['status'])
time.sleep(1)
response = client.check_status(message_id)
print(response['status'])
Basically, what I need is to add an input in a template "HTML File", this input get passed to the message variable in the code above, same with the number. I can easily do that with instances, but how can the below get executed when a button is clicked from the form in the template?
I'm kinda newbie in Django and still finding my way
Here is the tutorial that explains how to make the python file, but execute it from the shell, not a django application.
I hope I was clear describing my problem and any help would be appreciated!
All you need is a form with a message field. In a view, you want to show that form and when the user press submit, you want to execute your script.
Here is some pseudo-code:
urls.py
url('^my-page/' my_views.my_view, name='my-page'),
forms.py
SmsForm(forms.Form):
message = fields.CharField(...)
my_views.py
def my_view(request):
form = SmsForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
send_sms(form.cleaned_data['message']) # do this last
messages.success(request, "Success")
return HttpResponseRedirect(request.path)
else:
messages.warning(request, "Failure")
return render(request, 'my_template.html', {'form': form})
Check the Django documentation about urls, views, forms and messages and proceed step by step:
get the page to load
get the form to load
get the form submission to work and simply show "Success" or "Failure"
finally, write the send_sms function (you've almost done it)
Lets start from the dust cloud.
What you are asking is mostly about how the web pages work. You need to know how to pass parameters using HTML. There are lots of ways to do it. But with django there is a pattern.
You need a url, and a view to catch any requests. Then you need to create a template and a form inside it. With this form you could create some requests to send data to your view.
To create you need to edit urls.py inside your project add an url:
urls.py
from django.conf.urls import url
from my_app.views import my_view
urlpatterns = [
...
url(r'^my_url$', my_view, name='my_view')
...
]
For more about urls please look at URL dispatcher page at documentation.
Then create your view inside your app which is my_app in my example. Edit my_app/views.py
my_app/views.py
from django.http import HttpResponse
def my_view(request):
return HttpResponse('IT WORKS!')
This way you get a working view which could be accessed with path /my_url. If you run ./manage.py runserver you could access your view from http://localhost:8000/my_url.
To create a form you need to create a template. By default django searches app directories for templates. Create a templates directory in your app, in our case my_app/templates and create an HTML file inside. For example my_app/templates/my_form.html. But i advice to create one more directory inside templates directory. my_app/templates/my_app/my_form.html. This will prevent template conflicts. You can check Templates page at documentation for more.
my_app/templates/my_app/my_form.html
<html>
<body>
<form action="/my_url" method="POST">
{% csrf_token %}
<input type="text" name="number">
<input type="text" name="message">
<input type="submit" value="Run My Code">
</form>
</body>
</html>
This is the one of the ways of creating your form. But I do not recommend it. I will make it prettier. But first lets "Make it work", edit your views.py:
csrf_token is a django builtin template tag, to put CSRF token into your form. By default django requires CSRF tokens at every post
request.
my_app/views.py
from django.http import HttpResponse
from django.shortcuts import render
def my_view(request):
if request.method == 'GET':
return render('my_app/my_form.html')
elif request.method == 'POST':
# get post parameters or None as default value
number = request.POST.get('number', None)
message = request.POST.get('message', None)
# check if parameters are None or not
if number is None or message is None:
return HttpResponse('Number and Message should be passed')
# your code goes here
...
return HttpResponse('Your code result')
Till this point the purpose of this answer was "Making it work". Lets convert it nice and clean. First of all we would create Form. Forms are like models, which helps you create forms as objects. It also handles form validations. Forms are saved inside forms directory generally. Create my_app/forms.py and edit it:
my_app/forms.py
from django import forms
class MyForm(forms.Form):
number = forms.CharField(max_length=15, required=True)
message = forms.CharField(max_length=160, required=True)
Put your form inside your template:
my_app/templates/my_app/my_form.html
<html>
<body>
<form action="{% url 'my_view' %}" method="POST">
{% csrf_token %}
{{ form }}
</form>
</body>
</html>
Besides the form, the action of the HTML form tag is also changed.
url template tag is used to get url form url name specified in urls.py.
Instead of url tag, {{ request.path }} could have been used.
Create a form instance and pass it to the template rendering:
my_app/views.py
from django.http import HttpResponse
from django.shortcuts import render
from .forms import MyForm
def my_view(request):
if request.method == 'GET':
form = MyForm()
return render('my_app/my_form.html', {'form': form})
elif request.method == 'POST':
form = MyForm(request.POST)
# check if for is not valid
if not form.is_valid():
# return same template with the form
# form will show errors on it.
return render('my_app/my_form.html', {'form': form})
# your code goes here
...
return HttpResponse('Your code result')
You can use class based vies to write your view, but it's not necessary. I hope it helps.
You can create a view that takes up query parameters from the url and use it for further implementation. Then you can create a link/button in the html template which can redirect you to that url. For example:
in urls.py:
url(r'^run_a/(?P<msg>\w{0,25})/(?P<num>\w{0,25})/$', yourcode, name='get_msg'),
in template:
submit
in views.py:
def get_msg(request,msg,num):
message=msg
number=num
#rest of the code
Hope this helps :)

DJANGO - Redirect to different page from POST with data

I am trying to have a simple form that once filled, will direct to a different webpage or remain on the same page if invalid. The page should have a text box and submit form and once a user enters anything it should direct you to a separate page.
My directory structure is as follows:
appName/
app/
forms.py
urls.py
views.py
templates/
app/
goodbye.html
name.html
library.html
thanks.html
appName/
settings.py
urls.py
My app/urls.py is as follows:
from django.conf.urls import url
from . import views
app_name = 'app'
urlpatterns = [
url(r'^$', views.index2, name = 'index'),
url(r'^hello/$', views.hello, name = 'hello'),
url(r'^goodbye/$', views.goodbye, name = 'goodbye'),
#url(r'^library$', views.library, name = 'library'),
url(r'^library/$', views.library, name = 'library'),
url(r'^library/(?P<book_id>[0-9]+)/$', views.book, name = 'book'),
url(r'^getname/$', views.get_name, name = 'get_name'),
url(r'^your-name/$',views.get_name, name='get_name'),
url(r'^thanks/$',views.say_thanks,name='thanks'),
#url(r'^thanks/(?P<name_id>[a-zA-Z]+)/$', views.say_thanks,name='thanks'),
]
My forms.py is :
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label = 'Your name', max_length=100)
My app/views.py is:
from django.http import HttpResponse
from django.template import loader
from django.shortcuts import render
from django.http import HttpResponseRedirect
#forms
from .forms import NameForm
# Create your views here.
def index2(request):
return HttpResponse("hello world")
def hello(request):
text = """<h1>Welcome to my app! </h1>"""
return HttpResponse(text)
def goodbye(request):
template = loader.get_template("app/goodbye.html")
context = {
'output' : 'This is output from goodby views.py request handler'
}
return HttpResponse(template.render(context,request))
def library(request):
template = loader.get_template("app/library.html")
context = {
'output' : 'Welcome to the libary!!'
}
return HttpResponse(template.render(context, request))
def book(request, book_id):
return HttpResponse("You're looking at book %s. " % book_id)
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
#process the data in form.cleaned_data as required
locationGo = "/thanks/"
template = loader.get_template("app/thanks.html")
return HttpResponse(template.render({'name':'name'},request))
else:
form = NameForm()
template = loader.get_template("app/name.html")
context = {'form': form}
return HttpResponse(template.render(context, request))
def say_thanks(request):
template = loader.get_template("app/thanks.html")
return HttpResponse(template.render({'name': 'name'},request))
My templates include:
name.html :
<form action = "/getname/" method = "post">
{% csrf_token %}
{{ form }}
<input type = "submit" value = "Submit" />
</form>
goodbye.html
<h1>Goodbye to Template Romance</h1>
Go Back
thanks.html
Thanks {{name}}!
What I would like is for:
A user to visit to : website.com/getname/ to show the name.html file (which it does)
If a user hits submit to stay on the same page (website.com/getname/) (which it doesn't - it gives: ValueError at /getname/ ->The view app.views.get_name didn't return an HttpResponse object. It returned None instead.
If a user enters in the submit field, to be redirected to website.com/thanks/ (which it sort of does. It currently loads the thanks.html template, but the URL stays on website.com/getname/)
Inside the get_name(request): function, the POST and GET if...else doesn't seem to be firing based on the Submit button, and it doesn't seem to be loading the correct page, OR change the current URL address once it gets processed. I have tried using HttpRedirect() which works, however, I would also like to pass the forms data (which is another issue).
Any suggestions would be a big help!
Your first problem is that you are not returning a response when the request method is post and the form is invalid. You can fix that by changing the indentation of your view, so that you always return a response at the end of your view.
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
...
else:
form = NameForm()
template = loader.get_template("app/name.html")
context = {'form': form}
return HttpResponse(template.render(context, request))
If you want to redirect to the /thanks/ view, then you can use the redirect shortcut.
if form.is_valid():
return redirect('thanks')
Note that it isn't possible to redirect and pass the form data (see this question for an explanation). You should do any processing you want with the data before redirecting. You could use the messages framework to create a message 'Thanks <name>' before redirecting.
This works because you have name='thanks' in your url pattern.
You can simplify your views by using the render shortcut. Instead of
template = loader.get_template("app/name.html")
context = {'form': form}
return HttpResponse(template.render(context, request))
you can simply do:
return render(request, "app/name.html", context)
Remember to add the imports for the shortcuts:
from django.shortcuts import redirect, render

Multiple instances of the same form field

I have invite form with two fields defined as person and email as follows:
class InviteForm(Form):
person = TextField("person", validators=[validators.Required("Please enter persons name.")])
email = EmailField("email", validators=[validators.Required("Please enter valid email."), validators.Email("Please enter valid email.")])
def validate(self):
return validate_form(self)
Where validate_form function is a cusotm validator which check few conditions for invite.
My requirement is to allow users to invite more than one person at a time. To achieve this I have added jquery function which replicates these fields in html form and allow to invite multiple people.
But the problem is in my view function when I extract results from post request it gives only first persons information. How can I get all the persons details. My view is defined as follows:
#app.route("/invite", methods=["GET", "POST"])
def invite():
invite_form = InviteForm()
if invite_form.validate_on_submit():
print invite_form.person
print invite_form.email
This gives only one field, instead of array of fields.
Is this possible with python wtf? How?
What you're looking for is FormField which lets you build a list of the WTF Fields (or groups even).
Here's a simple example-- it'll render three string fields as a html list because that's the minimum required. If you want to add extras via javascript, then just adhere to the same naming scheme, in the case below, a fourth would have a name of person-3.
from flask import Flask, render_template_string
from flask.ext.wtf import Form
from wtforms import FieldList, StringField
app = Flask(__name__)
app.secret_key = 'TEST'
class TestForm(Form):
person = FieldList(StringField('Person'), min_entries=3, max_entries=10)
foo = StringField('Test')
#app.route('/', methods=['POST', 'GET'])
def example():
form = TestForm()
if form.validate_on_submit():
print form.person.data
## [u'One', u'Two', u'Three']
return render_template_string(
"""
<form method="post" action="#">
{{ form.hidden_tag() }}
{{ form.person }}
<input type="submit"/>
</form>
""", form=form)
if __name__ == '__main__':
app.run(debug=True)

getting html form data into django class based view

I have created a Class view in views.py of the django application.
class HelloTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HelloTemplate, self).get_context_data(**kwargs)
return context
Now I have a form defined in the html page:
<form method="get">
<input type="text" name="q">
<input type="text" name="q1">
<input type="submit" value="Search">
</form>
As you can see, I am submitting the form on the same page.
Now I want to get the form submitted values in my HelloTemplate class. I don't want to create another class or methods outside the existing class.
Also, I would like to send an error message to the html form if data is not validated in the django.
I don't know how to do this, please help me out.
You need to define get (because your form defined with get method <form method="get">) method in view class:
class HelloTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HelloTemplate, self).get_context_data(**kwargs)
return context
def get(self, request, *args, **kwargs):
q = request.GET.get('q')
error = ''
if not q:
error = "error message"
return render(request, self.template_name, {'error': error})
More information in django docs here Introduction to Class-based views
There's only one value, and it's in request.GET['q'].
Quick response, I can show you what I did a while ago for a review form (for people to create a new review, one of my models):
def review_form_view(request):
c = {}
c.update(csrf(request))
a = Review()
if request.method == 'POST':
review_form = Review_Form(request.POST, instance=a)
if review_form.is_valid():
a = review_form.save()
return HttpResponseRedirect('../dest_form_complete')
pass
else:
review_form = Review_Form(instance=a)
return render_to_response('../review_form.html', {
'review_form': review_form,
}, context_instance=RequestContext(request))
If you have a user model, comment model, etc. you can probably use something similar to this. Very (very) roughly put, the request is the input that the user fills out in the form, 'POST' is the method called that lets the server know you are adding entries to your database, and is_valid() validates the data according to your models.py parameters (can name be NULL? Is age an integer? etc).
Take a look at https://docs.djangoproject.com/en/dev/topics/forms/ as well for more examples and explanation.

Categories