I'm attempting to list a validation error on my HTML template if the form on that template isn't properly submitted. My forms.py file includes a function (clean_email) that will catch any string that's entered that doesn't include an "#" symbol, and it actually works. Therefore, any form that I attempt to submit without an "#" character in the email field won't be submitted.
Unfortunately, the error isn't displayed as it should be on my HTML template. The code for displaying it is in line 15 of contact.html (contactform.errors ). This code doesn't produce any results. Here are the relevant files:
Models.py
from __future__ import unicode_literals
from django.db import models
class Contact(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
phone_number = models.CharField(max_length=30, blank=True)
email = models.CharField(max_length=50)
message = models.TextField(default=" ")
Forms.py
from models import Contact
from django.forms import ModelForm
from django.core.exceptions import ValidationError
from django import forms
class ContactForm(ModelForm):
class Meta:
model = Contact
fields = "__all__"
def clean_email(self):
email = self.cleaned_data["email"]
if "#" not in email:
raise ValidationError("Not an Email Address")
return email
Views.py
from django.shortcuts import render
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from forms import ContactForm
def contact(request):
contactform = ContactForm()
if request.method == "POST":
contactform = ContactForm(request.POST)
if contactform.is_valid():
message = contactform.save(commit=False)
message.save()
return HttpResponseRedirect(reverse("contact"))
else:
print(contactform.errors)
contactform = ContactForm()
return render(request,"contact_form/contact.html",{"contactform":contactform})
Finally, Contact.HTML
{% block content %}
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="{% static "css/main.css" %}">
<link rel="stylesheet" href="{% static "css/contact.css" %}">
<div class="outer">
<form method="POST" action="">
{% csrf_token %}
<ul>
<li>
<label = for="email">Email</label>
{{ contactform.email }}
{{ contactform.errors }}
</li>
</ul>
<input type="submit" value="Submit Form"/>
</form>
</div>
{% endblock %}
Any ideas/help is appreciated, thanks!
Apart from using models.EmailField (which you should be doing) you need to change {{ contactform.errors }} to {{ contactform.email.errors }}
I figured it out. Before the validation error could even be raised, I was attempting to generate a brand new form.
contactform = ContactForm()
^That code in my views.py file would make it so an entirely new form was created on my HTML template. Once I got rid of it, everything worked like it should.
Related
I am trying to make a simple form in Django that accepts some file upload fields and a few float fields. However, when I run this in my browser, the is_valid() never gets triggered even when all forms are filled in. I have looked through the Django docs and have tried to recreate the examples as much as possible, but I can't figure out what is wrong. I know that the is_valid() is not true because the page does not redirect to another page when submit is pressed. Also, if I go into the admin page, no instances of MyModel are made.
Here is my code.
models.py:
from django.db import models
# Create your models here.
class MyModel(models.Model):
file1 = models.FileField()
file2 = models.FileField()
x = models.FloatField()
y = models.FloatField()
z = models.FloatField()
def __str__(self):
return self.file1
forms.py:
from django import forms
from django.forms import ModelForm
from .models import MyModel
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
views.py:
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect
from .forms import MyForm
# Create your views here.
def index_view(request):
if request.method == 'POST':
form = MyForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('some_page')
else:
form = DocumentsForm()
return render(request, 'index.html', {'form':form})
index.html:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<h1>Home Page!</h1>
<form method="POST" action="/">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="Submit">
</form>
</body>
</html>
My guess is it has to do with the fact that you haven't included enctype="multipart/form-data" in your <form> declaration in the HTML. It should look like this:
<form action="/" method="post" enctype="multipart/form-data" class="">
The multipart/form-data is necessary when uploading a file through forms.
Since you are sending both data and files, you need to specify the encoding of the form to:
<form enctype="multipart/form-data" method="POST" action="/">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="Submit">
</form>
I am building a registration form. Whenever a user fills the form and clicks the register button I want them to see the preview of their submissions. I am having problems with the arguments. Here goes my code:
models.py
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
# Create your models here.
class Register(models.Model):
regChoice = (
('Self', 'Self'),
('Group', 'Group'),
('Corporate', 'Corporate'),
('Others', 'Others'),
)
name = models.CharField(max_length=50)
email = models.EmailField(max_length=254,null=True)
phoneNumber = PhoneNumberField(null=True)
idCard = models.ImageField(null=True)
regType = models.CharField(max_length=25, choices=regChoice,null=True)
ticketNo = models.IntegerField(default=1)
def __str__(self):
return self.name
forms.py
from django import forms
from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import *
class RegisterForm(ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Your full name...'}))
email = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Your email...'}))
phoneNumber = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Your phone number...'}))
class Meta:
model = Register
fields = '__all__'
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='home'),
path('preview.html/<str:pk>', views.preview, name="preview")
]
views.py
from django.shortcuts import render, redirect
from .models import *
from .forms import *
# Create your views here.
def index(request):
form = RegisterForm()
if request.method == 'POST':
form = RegisterForm(request.POST, request.FILES)
if form.is_valid():
form.save()
context = {'form':form}
return render(request, 'event/index.html', context)
def preview(request, pk):
reg = Register.objects.get(id=pk)
prev = RegisterForm(instance=reg)
if request.method == 'POST':
form = RegisterForm(request.POST, instance=reg)
if form.is_valid():
form.save()
return redirect('/')
context = {'reg':reg, 'prev':prev}
return render(request, 'event/preview.html', context)
index.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Event Registration</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/script.js' %}"></script>
</head>
<body>
<div class="mobile-screen">
<div class="header">
</div>
<div class="logo"></div>
<form id="login-form" method="POST" action="{% url 'preview' form.id %}" enctype="multipart/form-data">
{% csrf_token %}
{{form.name}}
{{form.email}}
{{form.phoneNumber}}
<legend style="color: aliceblue;">Upload ID card: </legend>{{form.idCard}}
<div style="text-align: center; color: aliceblue;">Registration Type: {{form.regType}}</div>
{{form.ticketNo}}
<input class="btn btn-sm btn-primary" type="submit" value="Register" name="Register">
</form>
</div>
</body>
</html>
preview.html
Hello {{prev.name}},
your email is {{prev.email}}
your phone number is {{prev.phoneNumber}}
your idCard photo is {{prev.idCard.url}}
your registration type is {{prev.regType}}
your number of tickets is {{prev.ticketNo}}
The error I am having is:
NoReverseMatch at /
Reverse for 'preview' with arguments '('',)' not found. 1 pattern(s) tried: ['preview\.html/(?P[^/]+)$']
When someone reaches your index page and enters the form we need to
Submit the form as a POST request to index view
Save the form thereby creating a model in the DB
Redirect the user to preview view using the above id
To do that the code needs to be somewhat like this, I have not tested it, but you should get the idea.
from django.shortcuts import redirect
def index(request):
form = RegisterForm()
if request.method == 'POST':
form = RegisterForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save()
return redirect('preview', pk=instance.id)
context = {'form':form}
return render(request, 'event/index.html', context)
Inside your index.html change
action="{% url 'preview' form.id %}"
to
action=""
as we want it to post to the INDEX view as that is where out POST handling logic is.
The index view then redirects to preview using the newly generated object.
Also as mentioned by #Snir in the other answer, having .html in URLS is not a standard practice. It would be better to simple make it something like:
path('preview/<str:pk>', views.preview, name="preview")
The URL patterns are regexes, so you'll have to escape special regex characters, like the dot. Try (add r) or remove the dot:
path(r'preview.html/<str:pk>', views.preview,
name="preview")
I'm trying to create a form to unsubscribe newsletter subscribers, but I don't know exactly where I'm going wrong. The steps in my view all work in the command line so its hard for me to debug. When I submit the form on an existing email address the error is 'Subscriber with this email already exists', but I'm trying to delete an object not create one, and I'm a little stuck. Any help is much appreciated!
My View:
from subscribe.forms import SubscribeForm, UnsubscribeForm
from django.shortcuts import render, HttpResponseRedirect
from django.contrib import messages
from .models import Subscriber
from django.shortcuts import get_object_or_404
def unsubscribe(request):
if request.method == 'POST':
form = UnsubscribeForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
user = get_object_or_404(Subscriber,email=email)
user.delete(id=user.id)
messages.success(request, 'Unsubscribed')
return HttpResponseRedirect('/newsletter/subscribe/')
else:
messages.error(request, form.errors)
return render(request, 'unsubscribe.html', {'form': form})
else:
form = UnsubscribeForm()
return render(request, 'unsubscribe.html', {'form': form})
My forms:
from django.forms import ModelForm, EmailField
from .models import Subscriber
class SubscribeForm(ModelForm):
email = EmailField()
class Meta:
model = Subscriber
fields = ('email',)
class UnsubscribeForm(ModelForm):
email = EmailField()
class Meta:
model = Subscriber
fields = ('email',)
My Model:
from django.db import models
# Create your models here.
class Subscriber(models.Model):
email = models.EmailField(max_length=75, unique=True)
def __str__(self):
return self.email
My Template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">UnSubscribe</button>
</form>
</body>
</html>
I finally got a working view for the unsubscribe page. Not really different from before, but the difference was in the model, where I removed the unique constraint from the email field.
from django.db import models
# Create your models here.
class Subscriber(models.Model):
email = models.EmailField(max_length=75,)
def __str__(self):
return self.email
I'm trying to set up a form on Django that displays inputs on the page, but I get this error.
django.db.utils.OperationalError: no such table: firstapp_post
This doesn't happen right away, but when I try to use the submit feature on my form.
Right now this is what I have as my models:
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
post = models.CharField(max_length=500)
user = models.ForeignKey(User)
These are currently my forms:
from django import forms
from firstapp.models import Post
class IndexForm(forms.ModelForm):
post = forms.CharField()
class Meta:
model = Post
fields = ('post',)
This is my views file:
from django.shortcuts import render, redirect
from firstapp.forms import IndexForm
from django.views.generic import TemplateView
class HomePage(TemplateView):
template_name = 'home/home.html'
def get(self, request):
form = IndexForm()
return render(request, self.template_name, {'form': form})
def post(self, request):
form = IndexForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
text = form.cleaned_data['post']
form = IndexForm()
return redirect('home:home')
args = {'form': form, 'text': text}
return render(request, self.template_name, args)
This is my base.html
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Assignment 4</title>
<link rel='stylesheet' href='{% static "css/base.css" %}'/>
</head>
<body>
<p>{{ variable }}</p>
{% block body %}{% endblock %}
<script src= '{% static "js/base.js" %}'></script>
</body>
</html>
and my home.html:
{% extends 'base.html' %}
{% block body %}
<div class="container">
<p>Home</p>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
<p>{{ text }}</p>
</div>
{% endblock %}
Does anyone have any idea what this error even means or why I'm getting it? This has been driving me nuts. Thanks for the help!
As the error message mentions, that particular table does not exist in your database.
You can run the following command:
python manage.py makemigrations appname
By running makemigrations, you’re telling Django that you’ve made some changes to your models and that you’d like the changes to be stored as a migration.
Now run migrate again to create those model tables in your database
python manage.py migrate
Further Reading
I am very new to Django forms. I am trying to simply get a value from a text field and store it in a database. I am getting an error report saying:
*Forbidden (403)
CSRF verification failed.
Request aborted.
Reason given for failure:
CSRF token missing or incorrect.
For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function uses RequestContext for the template, instead of Context.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.*
Where am I going wrong?
My views.py code is:
from django.shortcuts import render
from feedback.models import Test
from mysite.forms import TestForm
from django.http import HttpResponse
from django.template import Context, loader
def test_view(request):
form = TestForm
t = loader.get_template('form.html')
c = RequestContext(request,{'n':''})
if request.method=='POST':
form = TestForm(request.POST)
if form.is_valid():
in_name = request.POST.get("firstname")
fd = Test(name = in_name)
fd.save()
return HttpResponse(t.render(c))
My models.py code is:
from django.db import models
from django.forms import ModelForm
class Test(models.Model):
name = models.CharField(max_length=255)
class TestForm(ModelForm):
class Meta:
model = Test
fields = ['name']
My forms.py code is:
from django import forms
class TestForm(forms.Form):
name = forms.CharField()
My HTML template is:
<!DOCTYPE html>
<html>
<head>
<title>test form</title>
</head>
<body>
<form method = "POST">
{% csrf_token %}
First name:<br>
<input type="text" name="firstname" value = {{ n }}>
<br><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
You do it in a wrong, very PHPish, way.
Move the form definition from models.py to the forms.py, so your feedback/forms.py should be:
from django.forms import ModelForm
class TestForm(forms.ModelForm):
class Meta:
model = Test
fields = ['name']
The feedback/views.py should be simplified to:
from django.shortcuts import render, redirect
from feedback.forms import TestForm
def test_view(request):
if request.method == 'POST':
form = TestForm(request.POST)
if form.is_valid():
form.save()
return redirect('.')
else:
form = TestForm()
return render(request, 'form.html', {'form': form})
And the template:
<!DOCTYPE html>
<html>
<head>
<title>test form</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
</body>
</html>