I started to learn Django today, but I am stuck at using forms. I have created two forms: /contact and /blog-new. The form at the Contact page is working fine, but the one at /blog-new is redirecting me to the home page after the submission button is pressed and no information is printed in the terminal nor saved in the database.
Code on Github
I appreciate if someone can explain to me what I did wrong as I cannot figure it out. Thank you!
mysite/blog/forms.py
from django import forms
from .models import BlogPost
class BlogPostModelForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['title', 'slug', 'content']
mysite/blog/views.py
from .forms import BlogPostModelForm
def blog_post_create_view(request):
# create objects
# ? use a form
# request.user -> return something
form = BlogPostModelForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = BlogPostModelForm()
template_name = 'form.html'
context = {'form': form}
return render(request, template_name, context)
mysite/blog/models.py
from django.db import models
# Create your models here.
class BlogPost(models.Model):
title = models.TextField()
slug = models.SlugField(unique=True)
content = models.TextField(null=True, blank=True)
mysite/mysite/urls.py
from blog.views import (
blog_post_create_view,
)
urlpatterns = [
..
path('blog-new', blog_post_create_view),
..
]
mysite/templates/form.html
{% extends "base.html" %}
{% block content %}
{% if title %}
<h1>{{ title }}</h1>
{% endif %}
<form method='POST' action='.'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Send</button>
</form>
{% endblock %}
You need to point to right url in action attribute of form.
<form action="/blog-new/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
I think it's not necessary in your case but you could also refactor your view to match the docs.
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import SomeForm
def some_view(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 = SomeForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = SomeForm()
return render(request, 'template_name.html', {'form': form})
You need to point to right url in action attribute of form.
That was not actually the solution but something that helped me to figure out what was wrong.
It is not necessary to point to /blog-new/ as . for action will point to the same page, but I have tried with /blog-new/ as action URL and I was surprised to see that /blog-new/ page doesn't exist.
The bug was in mysite/mysite/urls.py for missing a /:
path('blog-new', blog_post_create_view),
It is funny (and annoying) how a symbol like / missing from your code will mess up everything and make you spend hours trying to find a solution as simple as that.
Thank you for your time spend to have a look over my code and try to help me!
Related
I am trying to display a simple form (3 fields) on a webpage using Django but no fields are displaying - see code below.
I've gone through the Django doc, MDN doc, most of the StackOverflow posts here, but it's still not working.
I was able to see, using {% debug %}, that there is no object EmailInput on the page.
At this point, I am not sure what is causing this issue. Any help would be very much appreciated.
Thanks
forms.py
from django import forms
class EmailInput(forms.Form):
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
views.py
from django.shortcuts import render
from .models import journalEntry
from django.http import HttpResponseRedirect
from django.urls import reverse
from journal.forms import EmailInput
def index(request):
post = journalEntry.objects.filter(status__exact='f')
latest_post = journalEntry.objects.filter(status__exact='f').order_by('-created')[:5]
return render(request, 'journal_index.html', context = {'post':post,'latest_post':latest_post})
def email_input(request):
if request.method == 'POST':
form = EmailInput(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('journal-index'))
else:
form = EmailInput()
return render(request, 'journal_index.html',{'form':form})
journal_index.html
{% extends "base_generic.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit"/>
</form>
{% endblock content %}
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='journal-index'),
]
If you want to display it in the index page then you have to send it as a context variable in your index function. And now it will be available in your journal_index.html template file.
def index(request):
post = journalEntry.objects.filter(status__exact='f')
latest_post = journalEntry.objects.filter(status__exact='f').order_by('-created')[:5]
form = EmailInput()
context = {
'post': post,
'latest_post': latest_post,
'form': form
}
return render(request, 'journal_index.html', context = context)
The code from your email_input function is not called anywhere so there is no way this form could be displayed. Also you have to figure out where do you want to display this form. If you don't want to display it together with the stuff from your index page then you would have to create a new template file, add the form there and add a new url path to display that page.
It is because you are not even calling email_input.
you need to bind it to a url like this
urlpatterns = [
url(r'^$', views.email_input),
]
only my Submit button is popping up when i am trying to pass a form.
I even tried just copying the code from the Django website... Still does not work for me.
This is my forms.py
from django import forms
class contactForm(forms.Form):
name = forms.CharField(required=False, max_length=100, help_text='100 max.')
email = forms.EmailField(required=True)
comment = forms.CharField(required=True, widget=forms.Textarea)
This is my views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from .forms import contactForm
def contact(request):
form = contactForm(request.POST or None)
if form.is_valid():
print(request.POST)
context = locals()
return render(request, 'contact/contact.html', context)
def index(request):
return render(request, 'contact/contact.html')
This is my contact.html
{% extends "contact/base.html" %}
{% block content %}
<h1>Contact</h1>
<form method='POST' acion=''> {% csrf_token %}
{{ form.as_p }}
<input type='submit' value='submit form'/>
</form>
{% endblock %}
I really do not know what is wrong with this code...please help! Thanks
ps: I am new to python, maybe i need another version?
You have two views rendering the same template. One of them, contact, passes the form to the template. The other, index, does not, so there is nothing called form in the context and the result will be blank.
I'm new to Django. Even after reading, watching, and following many tutorials and guides, things still aren't coming together for me and I need help.
I'm making a very simple calculator app in preparation for a much more complicated calculator app that I will be refactoring/porting from a Python shell. The basic idea for the simply calculator is this: I have 4 pages on 1 app. They contain an add, subtract, multiply, and divide function respectively. I have a working side menu (using bootstrap and some copied code) to navigate between the pages. Each page has a form on it with two charfields and a submit button, and should return the result of the operation associated with the page. Right now I'm just focusing on the 'add' page since the others will just be a matter of copying.
Currently, I think I have a working form for getting two inputs, but I have no idea how to then get those two inputs as variables I can add to get the result.
Here's my code so far:
views.py
from __future__ import unicode_literals
from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from .forms import AddForm
#csrf_exempt
def web_adder(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 = AddForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# redirect to a new URL:
return web_adder_out(form)
# if a GET (or any other method) we'll create a blank form
else:
form = AddForm()
return render(request, 'addercontent.html', {'form': form})
def web_adder_out(request, form):
return render(request, 'addercontentout.html', {'content':[form.addend0 + form.addend1]})
#haven't gotten to this stuff yet
def web_subtracter(request):
return render(request, 'subtractercontent.html')
def web_multiplier(request):
return render(request, 'multipliercontent.html')
def web_divider(request):
return render(request, 'dividercontent.html')
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.web_adder, name='web_adder'),
url(r'^web_sub$', views.web_subtracter, name='web_subtracter'),
url(r'^web_mul$', views.web_multiplier, name='web_multiplier'),
url(r'^web_div$', views.web_divider, name='web_divider'),
]
forms.py
from django import forms
class AddForm(forms.Form):
addend0 = forms.CharField(label='first addend', max_length=100)
addend1 = forms.CharField(label='second addend', max_length=100)
addercontent.html
{% extends "header.html" %}
{% block content %}
<p>This is a web adder</p>
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
addercontentout.html
{% extends "header.html" %}
{% block content %}
{% for c in content%}
<p>Result: {{c}}</p>
{% endfor %}
{% endblock %}
(I know I'm not showing a lot of html files but they shouldn't matter)
In the above code I know the form in web_adder is different from the form in web_adder_out, that's where I'm at a loss. Although I wouldn't be surprised to see other mistakes.
I'm using Python 2.7.
Thanks in advance.
You can process each individual field in the form like so:
form.cleaned_data['field_name']
this gets you the actual value of the field.
Example with your form would be:
form.cleaned_data['addend0']
which will give you the POST value of addend0 field.
Hope this helps!
I have been going through the Django forms 'tutorial'. Once I had read through the tutorial, I tried modifying it to suit my needs and customize it to learn it Django forms well. I discovered whenever I modified the form, the website would not update. I assume its an error with my code, but I have not been able to find it.
# views.py
def contact(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 = ContactForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/message_recived/')
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(label='Name', max_length=100)
email = forms.EmailField(label='Email', max_length=100)
message = forms.CharField(label='Message', max_length=500)
# models.py
from django.db import models
class Contact(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
message = models.CharField(max_length=500)
and here is the contact.html template:
#contact.html
{% extends "BlogHome/headerAndFooter.html" %}
{% block content %}
<script>
document.title = "Pike Dzurny - Contact"
</script>
<form action="/message_recived/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
Did I do something wrong? I have tried clearing my browsers cache, using a new browser, and obviously refreshing it.
Looks like your forget to render response inside your view.
Also you need to include form into context to render template right.
Try to change view as follow:
def contact(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 = ContactForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/message_recived/')
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})
I've only been at python for about 2 weeks now and I've run into an issue which I've been trying to figure out for the past 3 days. I've read through the official documentation and pretty much every tutorial and youtube video available.
I'm trying to build a simple blog as a first project and would like to have a section where people can post comments. I have set up the comments model and a modelform to go along with it. However, I can't figure out how to get django to create the form for me in the template, nothing is displayed.
models.py
from django.db import models
from django.forms import ModelForm
class posts(models.Model):
author = models.CharField(max_length = 30)
title = models.CharField(max_length = 100)
bodytext = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.title
class comment(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
author = models.CharField(max_length = 30)
body = models.TextField()
post_id = models.ForeignKey('posts')
def __unicode__(self):
return self.body
class commentform(ModelForm):
class Meta:
model = comment
views.py
from django.shortcuts import render_to_response
from blog.models import posts, comment, commentform
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
def home(request):
entries = posts.objects.all()
return render_to_response('index.html', {'posts' : entries})
def get_post(request, post_id):
post = posts.objects.get(id = post_id)
context = {'post': post}
return render_to_response('post.html', context)
def add_comment(request, post_id):
if request.method == 'POST':
form = commentform(request.POST)
if form.is_valid():
new_comment = form.save(commit = false)
new_comment.post_id = post_id
new_comment.save()
else:
form = commentform()
context = RequestContext(request, {
'form': form})
return render_to_response('post.html', context)
Urls.py
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', 'blog.views.home', name='home'),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^(?P<post_id>.*)/$', 'blog.views.get_post'),
url(r'^post_comment/(\d+)/$','blog.view.add_comment'),
post.html
{% extends 'base.html' %}
{% block content %}
<p><h3> {{ post }} </h3></p>
<p> {{ post.bodytext }} </p>
<br><br><br><br>
<form action="/post_comment/{{ post.id }}/" method="POST"> {% csrf_token %}
{{ form }}
<input type="submit" value="Post">
</form>
{% endblock %}
I do get a 403 error CSRF verification failed but, the more pressing issue I think is that the {{ form }} doesn't do anything in the template.
I believe home function and get_post function are working and all the urls are working properly. So, I assume there's something wrong with the add_comment function or in posts.html.
Thanks
Django isn't magic. Your comment form is in a completely different view from the one that displays the blog post. So how is Django supposed to know to render it? You need to actually pass the form object to the template somehow.
The way that this was done in the old contrib.comments app was to have a simple template tag which was responsible for just displaying the comment form for an object, which you could place on any template. The form itself submitted to its own view as usual.
One thing you might check is the syntax of the render_to_response call. I believe you'll want to define it like this. (Maybe your syntax will work too, and this isn't the issue, but I have mostly seen the call made like this). This could be the cause of the missing form in the context.
return render_to_response('post.html',
{'form': form},
context_instance=RequestContext(request))
Let me know if this works. Hope this helps,
Joe
Reference: https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#django.shortcuts.render_to_response