My django modelform is letting the user submit the form without raising error even when the user hasn't submitted appropriate form, here it lets the user keep the email field blank.It doesn't save into the database because of is_valid() but the page refreshes and form goes blank again... Here is the code
models.py
from django.db import models
class MainForm(models.Model):
text = models.CharField(max_length=100)
email = models.EmailField(blank=False)
name = models.CharField(max_length=100,blank=False)
def __unicode__(self):
return self.email
forms.py
from django import forms
from .models import MainForm,new_model
class form_MainForm(forms.ModelForm):
class Meta:
model = MainForm
fields = '__all__'
views.py
def view_MainForm(request):
context = {
"form": form_MainForm
}
if request.method == 'POST' :
form_instance = form_MainForm(request.POST or None)
if form_instance.is_valid():
form_instance.save()
return render(request,'done.html',{'text':form_instance.cleaned_data.get('email')})
return render(request,'main_form.html',context)
template ->main_form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Main Form</title>
</head>
<body>
<form method="post" action=".">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
</body>
</html>
Your view function is wrong - you have to pass the invalid form to the context to get the error messages, ie:
def view_MainForm(request):
if request.method == 'POST' :
form_instance = form_MainForm(request.POST)
if form_instance.is_valid():
form_instance.save()
# here you should redirect to avoid
# re-submission of the form on page reload
# cf https://en.wikipedia.org/wiki/Post/Redirect/Get
return render(request,'done.html',{'text':form_instance.cleaned_data.get('email')})
else:
form_instance = form_MainForm()
context = {"form": form_instance}
return render(request,'main_form.html',context)
check this link to render error in your form https://docs.djangoproject.com/en/1.10/topics/forms/#rendering-form-error-messages , this will give an idea like why you are not able to save data.
when you are sending back the form it should be
context = {"form": form_MainForm(request.POST)} , this will display the form submitted values
Related
I'm probably lost in a glass of water but at the moment I can't figure it out. I'm working on a restaurant capstone project where the client is able to see a menu page, a purchase page and the owner of the restaurant after login is able to manage and enter a new recipe and create his personal menu. What I'm trying to do is: when the owner of the restaurant submits a POST request where he entered the recipe, i want that the recipe appear also in the page where is the menu. In this way is able to update new recipe and change maybe the old one. (I copy model, form and view code for a complete overview):
form.py
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
fields = '__all__'
model.py
class Recipe(models.Model):
name = models.CharField(max_length=50)
ingredients = models.CharField(max_length=500)
def __str__(self):
return self.name
View.py
def recipeEntry(request):
recipe_menu = Recipe.objects.all()
form = RecipeForm()
if request.method == 'POST':
form = RecipeForm(request.POST)
if form.is_valid():
form.save()
return redirect("recipe")
context = {'form':form, 'recipe_menu':recipe_menu}
return render(request, 'inventory/recipe.html', context)
recipe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Recipe</title>
</head>
<body>
<form method="post", action="">{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Add Recipe">
</form>
{% for rec in recipe_menu %}
<div>
<p>Recipe: {{rec.name}}</p>
<p>Ingredient :{{rec.ingredients}}</p>
</div>
{% endfor %}
</body>
</html>
At the moment the part of submitting the POST request it works so is only the second part that don't works. I tried a bit few solution but i don't understand what to do. I thought also to create a GET view for the menu page but i need to pass an URL for get the data and i didn't works.
Thank you very much for the help.
You must try with explicitly instantiate empty form when it's not a post request :
def recipeEntry(request):
recipe_menu = Recipe.objects.all()
# form = RecipeForm() Not here yet
if request.method == 'POST':
# Instantiate form with request.POST
form = RecipeForm(request.POST)
if form.is_valid():
form.save()
return redirect("recipe")
else: # Explicitly write else block
# Instantiate empty form for get request
form = RecipeForm()
context = {'form':form, 'recipe_menu':recipe_menu}
return render(request, 'inventory/recipe.html', context)
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")
from django import forms
from django.core import validators
class FormName(forms.Form):
name = forms.CharField()
email = forms.EmailField()
verify_email = forms.EmailField(label = "enter your email Again")
text = forms.CharField(widget = forms.Textarea)
def clean(self):
all_clean_data = super().clean()
email = all_clean_data['email']
vmail = all_clean_data['verify_email']
if email != vmail:
raise forms.ValidationError("Error i Email matching")
views.py
from django.shortcuts import render
from . import form
# Create your views here.
def index(request):
return render(request,'basicapp/index.html')
def form_name_view(request):
forms = form.FormName()
if request.method == "POST":
formObject = form.FormName(request.POST)
if formObject.is_valid():
print("Sucess!!!!!")
print(formObject.cleaned_data['name'])
print(formObject.cleaned_data['email'])
print(formObject.cleaned_data['text'])
return render(request,'basicapp/form_page.html',{'form':forms})
form_page.html
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Forms</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body>
<div class = "container">
<h1>Fill out the form</h1>
<form method="POST">
{{form.as_p}}
{% csrf_token %}
<input type="submit" class="btn btn-primary" value = "Submit">
</form>
</div>
</body>
</html>
I am Not sure What I am missing,
I have done everything and had done enough research, But could not find the solution.
Am I missing something because of the versioning of django.
I am following one udemy course and didn't get response, Thats y I am posting here.
Thanks in advance
The issue was in your views, you were not rendering the form object properly.
try this,
def form_name_view(request):
if request.method == "POST":
formObject = form.FormName(request.POST)
if formObject.is_valid():
print("Sucess!!!!!")
# do some redirection
else:
# if a GET (or any other method) we'll create a blank form
formObject = form.FormName()
return render(request, 'basicapp/form_page.html', {'form': formObject})
So, I've been trying hard, getting values from input fields in my custom form.
I have a url that corresponds to the form and that form redirects it to the same form again.
The view of the form url checks whether the request method is Post. If it is, then I declare a variable equal to request.POST, I then assigned those values to my model- item_description(). Here is the code of the views.py:
def addItem(request):
if request.method == "POST":
data = request.POST
print(data.__dict__)
item_description(item_name=data.item_name, item_number=data.item_number, item_quantity=data.item_quantity)
else:
HttpResponse("Something went wrong!")
return render(request, 'ims/addItemForm.html')
HTML form:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IMS| Add Item</title>
</head>
<body>
<form action="{% url 'Item-addition' %}" method="post">
{% csrf_token %}
<input type="text" name="item_name" placeholder="Enter Item Name">
<input type="text" name="item_number" placeholder="Enter Item Number">
<input type="text" name="item_quantity" placeholder="Enter Item Quantity">
<button type="submit" name="add" value="add">Add Item</button>
</form>
See items
</body>
</html>
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('add_item', views.addItem, name='Item-addition'),
path('items', views.itemsList, name='Items-list'),
]
models.py:
from django.db import models
class item_description(models.Model):
item_name = models.CharField(max_length=200)
item_number = models.CharField(max_length=200)
item_quantity = models.CharField(max_length=200)
def __str__(self):
return self.item_name
Also, I printed out the request which is a dictionary, but it was not having any of the values. Here is the printed request dictionary: {'_encoding': 'utf-8', '_mutable': False}.
Here is the error which I am getting:
File "/home/zaid/inventoryManagement/venv/src/ims/views.py", line 13, in addItem
item_description(item_name=data.item_name, item_number=data.item_number, item_quantity=data.item_quantity)
AttributeError: 'QueryDict' object has no attribute 'item_name'
Please help me getting values from the input fields.
Your mistakes:
item_description(item_name=data.item_name, item_number=data.item_number, item_quantity=data.item_quantity)
data is a QueryDict, so you must access the data in it using data['item_name'] or data.get('item_name') as you would for a regular dict.
item_description(...) doesn't actually do anything. It does not save anything to the database. To save to the database, you must use item_description.objects.create(...).
Other problems with your code:
you render the form fields on your own
you extract the POST data on your own
you attempt to save to the database on your own
you are missing input validation (what if some required values are missing? e.g. what if item_name is not submitted?)
you did not provide a suitable error message as feedback to the user if he/she enters inappropriate values (e.g. a string of length 201).
Django's ModelForm is able to handle all of these issues, so please use ModelForm instead.
If models.py is this:
from django.db import models
class ItemDescription(models.Model):
item_name = models.CharField(max_length=200)
item_number = models.CharField(max_length=200)
item_quantity = models.CharField(max_length=200)
def __str__(self):
return self.item_name
Then, create a ModelForm in forms.py:
from django import forms
from .models import ItemDescription
class ItemDescriptioneForm(forms.ModelForm):
class Meta:
model = ItemDescription
fields = ['item_name', 'item_number', 'item_quantity']
In your views.py, use the ModelForm you just created:
from django.shortcuts import render, redirect
from .forms import ItemDescriptionForm
def addItem(request):
if request.method == 'POST':
form = ItemDescriptionForm(request.POST)
if form.is_valid():
form.save()
return redirect('Items-list')
else:
form = ItemDescriptionForm()
return render(request, 'ims/addItemForm.html', {
'form': form,
})
Show the form in your template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Add Item</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" />
</form>
</body>
</html>
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>