I have done what is written on Django Documentation and I have tried several Youtube tutorials, including Stackoverflow's advice. However, I could not make the message "Validation Error" appear on the template. When I click the button to create a post with bad_word, I redirect to the same page, the post isn't saved but the form doesn't show me the message. I tried to save in a print( form.errors ) in the view and the terminal showed the message that I want to see in the template. So I don't know what I'm doing wrong...
view.py
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
content = form.cleaned_data['content']
username = User.objects.get(username=f"{request.user}")
new_post = Post(user=username, title=title, content=content, datetime=timezone.now())
new_post.writeOnChain()
cache.expire("cache", timeout=0)
return HttpResponseRedirect("/")
else:
form = PostForm()
return render(request, "api/homepage.html", {'form': form, 'postList': postList})
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'content',)
def clean_title(self):
title = self.cleaned_data['title']
if "bad_word" in title:
raise forms.ValidationError("Error")
return title
def clean_content(self):
content = self.cleaned_data['content']
if "bad_word" in content:
raise forms.ValidationError("Error")
return content
template
<div class="p-3 forms m-3">
<form class="crispy" action="{% url 'homepage' %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" class="btn buttons" value="Create Post">
</form>
</div>
terminal print
<ul class="errorlist"><li>content<ul> class="errorlist"><li>Error</li></ul> </li></ul>
If your form is invalid you always redirect to "/" without form information. Your return redirect needs to be indented with the rest of the "valid" form code.
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
content = form.cleaned_data['content']
username = User.objects.get(username=f"{request.user}")
new_post = Post(user=username, title=title, content=content, datetime=timezone.now())
new_post.writeOnChain()
cache.expire("cache", timeout=0)
return HttpResponseRedirect("/") # this line here
else:
Related
I have an update form to update information. Here problem is, product_title is updating but product_image is not working. Where is the problem that's for why the photo is not updating?
views.py:
def update_product(request,id):
product = Products.objects.get(pk=id)
form = update_product_info(request.POST or None, instance=product)
if request.method == 'POST' and form.is_valid():
form.save()
print(form.errors)
messages.success(request,"Successfully product information updated.")
return redirect("my_products")
context = {
'product':product,
"form":form
}
return render(request, "update_product.html", context)
update form:
class update_product_info(forms.ModelForm):
class Meta:
model = Products
fields = ('product_title','product_image')
widgets = {
'product_title':forms.TextInput(attrs={'class':'form-control', 'style':'font-size:13px;'}),
'product_image':forms.FileInput(attrs={'class':'form-control', 'style':'font-size:13px;'})
}
template:
<form action="" method="POST" class="needs-validation" style="font-size: 13px;" novalidate="" autocomplete="off" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<div class="d-flex align-items-center">
<button type="submit" class="btn btn-outline-dark ms-auto" value="Update" style="font-size: 13px;">Add</button>
</div>
You should pass both request.POST and request.FILES to the form:
from django.shortcuts import get_object_or_404
def update_product(request, id):
product = get_object_or_404(Products, pk=id)
if request.method == 'POST':
form = update_product_info(request.POST, request.FILES, instance=product)
if form.is_valid():
form.save()
messages.success(request, 'Successfully product information updated.')
return redirect('my_products')
else:
form = update_product_info(instance=product)
context = {'product': product, 'form': form}
return render(request, 'update_product.html', context)
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.
Note: normally a Django model is given a singular name, so Product instead of Products.
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use ProductInfoForm instead of
update_product_info.
I'm trying to make model based form but something went wrong.
model:
class Topic(models.Model):
name = models.CharField(max_length=200)
icon = models.ImageField(upload_to = 'images/')
form:
class TopicCreationForm(ModelForm):
class Meta:
model = Topic
fields = '__all__'
view:
def TopicCreateView(request):
form = TopicCreationForm()
if request.method == 'POST':
form = TopicCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It displays in console
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
my form html part
<form method="POST">
{% csrf_token %}
<fieldset >
<legend> New Topic</legend>
{{ form|crispy }}
</fieldset>
<div>
<input type="submit" value="submit" class="button-33" role="button">
</div>
</form>
where did i make mistake ?
You need to pass both request.POST and request.FILES [Django-doc], so:
def topic_create(request):
if request.method == 'POST':
form = TopicCreationForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
print('aaa') # It display in console
else:
form = TopicCreationForm()
context = {'form':form}
return render(request, 'blog/topic_form.html', context)
In the HTML form, you need to specify that the files should be encoded with the enctype="…" attribute [mdn]:
<form method="post" enctype="multipart/form-data">
…
</form>
To new readers: Neverwalkaloner's solution solved the initial error but the photo upload is still required and making required false in forms.py gives me a MultiValueDictKeyError. Any help on making it optional would be greatly appreciated.
I have a model and form to upload either a picture and text, or just text. My intention, actually was to make it a choice between an image, text or both and any help with that would be appreciated, but I digress. Uploading only works when an image is included, if it is just text, I get the error:
The view lesyeux.views.posts didn't return an HttpResponse object. It
returned None instead.The view lesyeux
My model is:
class Post(models.Model):
image = models.ImageField(upload_to='uploaded_images', blank=True,
null=True)
text_post = models.CharField(max_length=1000)
author = models.ForeignKey(User)
My form is:
class PostForm(forms.ModelForm):
image = forms.FileField(label='Select an image file',
help_text='Please select a photo to upload')
text_post = forms.CharField(help_text="Please enter some text.")
class Meta:
model = Post
fields = ('image', 'text_post',)
exclude = ('author',)
My view is:
def posts(request, id=None):
neighborhood = get_object_or_404(Neighborhood, id=id)
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = Post(image = request.FILES['image'])
post = form.save(commit=False)
post.author = request.user
post = post.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
else:
form = PostForm()
posts = Post.objects.all().order_by('-id')
return render(request, 'posts.html', context = {'form':form,
'posts':posts, 'neighborhood':neighborhood})
and my form is:
<form id="PostForm" method="post" action="/view/{{ neighborhood.id }}/posts/" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="hidden" name="next" value="{{ request.path }}">
<input type="submit" name="submit" value="Post" />
</form>
Your view doesnt return response if form is not valid. To fixt it rewrite view like this:
def posts(request, id=None):
neighborhood = get_object_or_404(Neighborhood, id=id)
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = Post(image = request.FILES['image'])
post = form.save(commit=False)
post.author = request.user
post = post.save()
next = request.POST.get('next', '/')
return HttpResponseRedirect(next)
else:
form = PostForm()
posts = Post.objects.all().order_by('-id')
return render(request, 'posts.html', context = {'form':form, 'posts':posts, 'neighborhood':neighborhood})
I'm trying to allow users to create category and post(that will be tagged to some category) I think I wrote the code right, but I'm getting 404 error with No Post matches the given query.
Here is my code.
this is my form
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="aa")
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput, required=False)
class Meta:
model = Category
fields =('name',)
class PostForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="bb")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Post
fields = ['title', 'content', 'image', 'views', 'category']
this is my view
#for adding category
def add_category(request):
if request.method == 'POST':
form = CategoryForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print form.errors
else:
form = CategoryForm()
return render(request, 'main/add_category.html', {'form':form})
#for adding post/see diff style :)
def add_post(request):
context = RequestContext(request)
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit=True)
return redirect(index)
else:
print form.errors
else:
form = PostForm()
return render_to_response('main/add_post.html', {'form':form}, context)
And this is my url
url(r'^add_post/', views.add_post, name='add_post'),
url(r'^add_category/$', views.add_category, name='add_category'),
]
And finally my templates
{
% extends 'base.html' %}
{% block content %}
<form id="post_form" method="post" action="/main/add_post/" enctype="multipart/form-data">
{% csrf_token %}
{{form}}
<input type="submit" name="submit" value="Create Post">
</form>
{% endblock %}
You should use action="{% url 'main:add_post' %}" instead of action="/main/add_post/".
Also check that in your projects's urls.py main app's urls included with namespace like
url(r'^main/', include('main.urls', namespace="main"))
If you don't use namespace, than change to action="{% url 'add_post' %}".
If error reoccurs, please provide more information.
Which ulr exactly you enter in browser to get this error?
Your template makes the form post to main/add_post/ while your url for the view is add_post/. You should make them consistent.
I have register function, it is displayed on every pages in my project using context_processors.
How to display errors if my form is not valid in my modal box in base.html?
Now errors is displayed in: /register/ subpage.
views.py
def UserRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/showcase/')
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'], email= form.cleaned_data['email'], password = form.cleaned_data['password'])
user.save()
klient = ClientProfile(user=user, name= form.cleaned_data['name'], address= form.cleaned_data['address'], zip_code=form.cleaned_data['zip_code'], city=form.cleaned_data['city'], tel= form.cleaned_data['tel'] )
klient.save()
return HttpResponseRedirect('/')
return render_to_response('registration.html', {'form':form}, context_instance=RequestContext(request))
else:
form = RegistrationForm()
context= {'form':form}
return render_to_response('registration.html', context, context_instance=RequestContext(request))
context_processors.py
from content.forms import *
def include_register_form(request):
form = RegistrationForm()
return {'register_form':form}
base.html
<div class="modalBox" id="modalRegister">
<div class="modalBox_iks"></div>
<div class="titleShowcase">Register</div>
<form method="POST" action="/register/">{%csrf_token%}
{{register_form}}
<input type="submit" value="Register">
</form>
</div>
It is possible?
You need to post your data with Ajax call, Showing errors in modal need Ajax call.
Or you can use third party app to enable Ajax form validation
what version of django are you using? If you are in django 1.5, use FormView.
view.py
class UserRegistration(FormView):
template_name = 'form_registration.html'
def render_to_response(self, context):
if self.request.user.is_authenticated():
return redirect('other_page')
return super(UserRegistration, self).render_to_response(context)
def form_valid(self, form):
# Here you know that you form is valid
user = User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
user.save()
klient = ClientProfile(user=user, name= form.cleaned_data['name'], address= form.cleaned_data['address'], zip_code=form.cleaned_data['zip_code'], city=form.cleaned_data['city'], tel= form.cleaned_data['tel'] )
klient.save()
return redirect('home') #I'm not sure that this really redirect you
Now write a 'form_registration.html' template where you show the errors. see here
And in your 'base.html'
<div class="modalBox" id="modalRegister">
<div class="modalBox_iks"></div>
<div class="titleShowcase">Register</div>
<form method="POST" id="ajax_form"action="/register/">{%csrf_token%}
{% include "form_registration.html" with form=form %}
<input type="submit" id="ajax_form_submit"value="Register">
</form>
</div>
Now, for your ajax, you can use this jquery plug-in.
You can set the 'target' option to override with the server response
Maybe that javascript help you:
<script>
$('#modalRegister').click("#ajax_form_submit", function(event){
event.preventDefault();
$('#ajax_form').ajax_form(target:'#ajax_form').submit();
})
</script>
I've used that plugin, it works fine.
hope that help!