I recently tried the forms validations and faced an issue with ValidationError().
The form error does not appear in my website when I submit the form.
Here is the code:
forms.py
class ArticleForm(forms.ModelForm):
def clean_titre(self):
titre = self.cleaned_data['titre']
if len(titre) < 5:
raise ValidationError('myError')
return titre
form = ArticleForm()
template.html
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
views.py
def AddArticle(request):
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
save_it = form.save(commit=False)
save_it.user = request.user
save_it.save()
form.save_m2m()
return HttpResponseRedirect('/')
What did I do wrong?
--- EDIT ---
Full template.html
<form class="form" action="{% url "article.views.AddArticle" %}" method="post" enctype='multipart/form-data'>
{% csrf_token %}
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
<div class="form-group">SUMMARY
{{ form.media }}
{{ form.summary.errors }}
{{ form.summary }}
</div>
<div class="form-group">CONTENU
{{ form.media }}
{{ form.contenu.errors }}
{{ form.contenu }}
</div>
<div class="form-group">
{{ form.image.errors }}
{{ form.image }}
</div>
<div class="form-group">TAGS
{{ form.tags.errors }}
{{ form.tags }}
</div>
<input type="submit" class="btn btn-default" value="Submit" autocomplete="off" autocorrect="off" />
</form>
I'll post the full forms.py too, it may help.
forms.py
class ArticleForm(forms.ModelForm):
def clean_titre(self):
titre = self.cleaned_data['titre']
if len(titre) < 5:
raise ValidationError('myError')
return titre
class Meta:
model = Article
exclude = ['date', 'rating', 'user']
widgets={
"titre":forms.TextInput(attrs={'placeholder':'Le titre', 'class':'form-control'}),
"contenu":forms.Textarea(attrs={'placeholder':'Le Contenu de votre message', 'class':'form-control'}),
"image":forms.FileInput(attrs={'placeholder':'Votre Image', 'id':'uploadBtn'}),
"tags":TagWidget(attrs={'placeholder':'Vos Tags', 'class':'form-control'}),
}
form = ArticleForm()
You are missing the else portion within your view. Here is the general flow of what forms usually do:
Users navigate to a page via GET which presents them with a form
Users fill in the form and submit it by using POST
If the form is valid, users are directed to a different page
If the form is not valid, users are presented with the same page as in step 1 with the validation errors displayed. After users correct them, they are process to step 2.
Here is that flow in django view:
def AddArticle(request):
if request.method == 'POST':
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
save_it = form.save(commit=False)
save_it.user = request.user
save_it.save()
form.save_m2m()
return HttpResponseRedirect('/')
else:
form = ArticleForm()
return render(request, 'template.html', {'form': form'})
I would however look into using class based views in Django. Initially they can seem very confusing but over time you will learn to appreciate them. Docs. Another useful resource when learning CBV.
By using CBV, the above can be simplified to:
class AddArticleView(CreateView):
success_url = 'name_of_view_here'
form_class = ArticleForm
template_name = 'template.html'
# urls.py
urlpatterns = patterns('', url(r'^articles/add/$', AddArticleView.as_view()))
Template
You also need to include the overall form error in the template, in addition to each field errors:
<form class="form" action="{% url "article.views.AddArticle" %}" method="post" enctype='multipart/form-data'>
{% csrf_token %}
{{ form.non_field_errors }}
...
</form>
Please note that you might need to wrap the errors with some bootstrap markup. More info in docs
Related
if there's anyone who knows how can I delete images user, I made a code to do that but I cannot continue I get some stuck. so if anyone could tell me which way can I make it this method?
also, I need to know about the outputs of (userprofile) in (delete_avatar) if this code is true how can I know it? I tried using print and repr but I didn't find this useful. so, anybody can get me help?
views.py
# Update Avatar
#login_required
def add_avatar(request, user_id):
my_logo = request.user.userprofile
form = AddAvatar(instance=my_logo)
get_userid = UserProfile.objects.filter(user_id=user_id)
context = {'form': form, 'get_userid': get_userid}
if request.method == 'POST':
form = AddAvatar(request.POST, request.FILES, instance=my_logo)
if form.is_valid():
form.save()
return redirect('account:view_profile')
return render(request, 'account/change-image.html', context)
# Remove Avatar
#login_required
def delete_avatar(request, user_id):
my_request = request.POST.get('rm-img')
userprofile = UserProfile(my_request)
pdb.set_trace()
if request.method == "POST":
del_img = UserProfile.objects.get(user_id=user_id).logo.delete() # delete object
return redirect('account:view_profile')
return render(request, 'account/change-image.html')
change-image.html
{% extends 'base.html' %}
{% block title %} Add New Image {% endblock %}
{% block body %}
<!-- Add new image for user-profile -->
<div class="change-image">
<div class="add-image">
<div class="container">
<h1>This Image Is Current, <br>Choose Your Image From Your Personal Computer Or Delete</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<label>{{ user.first_name }} {{ user.last_name }}</label>
{{ form.as_p }}
<button type="submit" class="btn btn-success">Change Now</button>
<input type="submit" name="rm-img" class="btn btn-danger" value="Remove Image">
</form>
</div>
</div>
</div>
{% endblock %}
the file html above where I can make a form to update and delete the user image
urls.py
urlpatterns = [
path('new-image/<int:user_id>/', views.add_avatar, name="add_avatar"),
path('del-image/', views.delete_avatar, name="delete_avatar"),
]
forms.py
class AddAvatar(forms.ModelForm):
class Meta:
model = UserProfile
fields = ['logo']
I'm new in Django and it's just a test for further model. I'm trying to pass a form from generic.FormView to generic.DetailView, and exhibit the datas inserted in the previous HTML (associated with the FormView) to another HTML (associated with the DetailView). I've thought it probably a problem with the link between the view.py and urls.py. The codes are:
views.py:
class IndexView(generic.FormView):
template_name = 'dutos/index.html'
form_class = GetDate
success_url = 'dutos/detail.html'
#def form_valid(self, form):
#return HttpResponse(self.success_url)
#return super.form_valid(form)
class DetailView(generic.DetailView):
model = Dutos
template_name = 'dutos/detail.html'
forms.py
class GetDate(forms.Form):
dateDataInicial = forms.DateTimeField(label='dataInicial', initial=datetime.now().strftime("%d/%m/%Y %H:%M:%S"), required=False)
dateDataFinal = forms.DateTimeField(label='dataFinal', initial=datetime.now().strftime("%d/%m/%Y %H:%M:%S"), required=False)
urls.py:
from django.urls import path
from .views import views
urlpatterns = [
path('', views.IndexView.as_view(), name="index"),
path('detail/', views.DetailView.as_view(), name="detail"),
]
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
</head>
<body>
<h1>Teste HTML</h1>
<div class="container-fluid" id="wrapper">
<div class="row">
<form action="/detail/" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<div class="fieldWrapper">
{{ form.dateDataInicial.errors }}
<label for="{{ form.dateDataInicial }} Data Inicial: </label>
{{ form.dateDataInicial }}
</div>
<div class="fieldWrapper">
{{ form.dateDataFinal.errors }}
<label for="{{ form.dateDataFinal }} Data Final: </label>
{{ form.dateDataFinal }}
</div>
<input type="submit" value="Pesquisar">
</div>
</form>
</div>
</div>
</body>
</html>
detail.html:
<!DOCTYPE html>
<html>
<head>
<title>Template</title>
</head>
<body>
<h1>Template HTML</h1>
{{form.cleaned_data['dateDataInicial']}}
{{form.cleaned_data['dateDataFinal']}}
</body>
</html>
I've already change the "{{form.cleaned_data['dateDataInicial']}}" to "form.dateDataInicial", or just cleaned everything and put "Test" to exhibit a simples HTML. I'm getting HTTP Error 405.
There's really quite a lot wrong with the code you've posted.
You're getting 405 because the form in your index template attempts to post directly to the detail URL, which is not set up to accept POST requests. An additional problem with doing this is that the form will not be validated, because the validation is supposed to happen in the IndexView, not the DetailView. Plus, the DetailView does not know anything about the form, so form.cleaned_data would not exist in the template context; and, Django template syntax does not support dictionary lookup via square brackets, so {{ form.cleaned_data['dateDataInicial'] }} would not work.
In order for validation to work you need to submit the form back to IndexView, which will then redirect to the detail view. (Another issue with your code is that success_url should be a URL, not a template path.) The problem then becomes how to get the data from one view to the other; the session is a good way to do that. So:
class IndexView(generic.FormView):
template_name = 'dutos/index.html'
form_class = GetDate
success_url = reverse_lazy('detail')
def form_valid(self, form):
self.request.session['dates'] = form.cleaned_data
return super.form_valid(form)
change the form tag in index.html:
<form action="" method="post">
the detail view:
class DetailView(generic.DetailView):
model = Dutos
template_name = 'dutos/detail.html'
def get_context_data(self, **kwargs):
kwargs['dates'] = self.request.session.pop('dates', {})
return super().get_context_data(**kwargs)
and in detail.html:
{{ dates.dateDataInicial }}
{{ dates.dateDataFinal }}
Thanks to the help of Daniel and his code, I figured out the modifications that lead to my needs. I've changed the genericView of DetailView from "generic.DetailView" to "generic.ListView". When it was made another problem appeared. To pass "datetime" through JSON, it convert to string format and all the date was being treated as string, so I lost the possibility to show the two dates in separated fields in detail.html. To overcome this problem, I adapted the solution proposed to Daniel, and divided the field in two so I can get it by form.cleaned_data and converted it into string, and now I don't need to worry about JSON serializing a "datetime".
views.py:
class IndexView(generic.FormView):
template_name = 'dutos/index.html'
form_class = GetDate
success_url = reverse_lazy('detail')
def form_valid(self, form):
#self.request.session['dates'] = json.dumps(form.cleaned_data, cls=DjangoJSONEncoder)
self.request.session['dateInicial'] = str(form.cleaned_data['dateDataInicial'])
self.request.session['dateFinal'] = str(form.cleaned_data['dateDataFinal'])
return super().form_valid(form)
class DetailView(generic.ListView):
model = Dutos
template_name = 'dutos/detail.html'
def get_context_data(self, **kwargs):
#kwargs['dates'] = self.request.session.pop('dates', {})
kwargs['dateInicial'] = self.request.session.pop('dateInicial', {})
kwargs['dateFinal'] = self.request.session.pop('dateFinal', {})
return super().get_context_data(**kwargs)
index.html:
<div class="container-fluid" id="wrapper">
<div class="row">
<form action="" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div>
<div class="fieldWrapper">
{{ form.dateDataInicial.errors }}
<label for="{{ form.dateDataInicial }} Data Inicial: </label>
{{ form.dateDataInicial }}
</div>
<div class="fieldWrapper">
{{ form.dateDataFinal.errors }}
<label for="{{ form.dateDataFinal }} Data Final: </label>
{{ form.dateDataFinal }}
</div>
<input type="submit" value="Pesquisar">
</div>
</form>
</div>
</div>
detail.html:
<body>
<h1>Detalhes</h1>
{{ dateFinal }}
<br>
{{ dateInicial }}
</body>
I have 2 models in my system:
class Display(models.Model):
name = models.CharField
UE = models.CharField
description
class Register(models.Model):
temp1 = models.FloatField()
temp2 = models.FloatField()
flow = models.FloatField()
I create displays using for inside a template, but the value of each display is a respective field in Register model. I can't make the loop with Register because i use only row (i can't loop fields). Understand?
Take a look of my code:
View:
def main(request):
dp_col = Display.objects.all()
reg = Registers.objects.latest('pk')
context = {
'dp_col': dp_col,
'reg':reg
}
return render(request,'operation.html',context)
Template:
{% for dp in dp_col %}
<div class='col-md-6'>
<div class="display-content">
<div class="display-data">
<h3 class="text-center display-desc">{{dp.name}}
<span>:</span>
<span class="text-center display-value">I need put the value of each field here</span>
<span class='display-unit'> {{dp.UE}}</span>
</h3>
</div>
</div>
</div>
{% empty %}
<!--colocar alguma coisa aqui, caso não tenha nada no for-->
{% endfor %}
Any ideas?
Thanks a lot!
This can be easily solved by using a Django Forms:
yourapp/forms.py
from django import forms
class DisplayForm(forms.ModelForm):
class Meta:
model = Display
fields = '__all__'
yourapp/views.py
from .forms import DisplayForm
def main(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 = DisplayForm(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 = DisplayForm()
return render(request, 'operation.html', {'form': form})
In operations.html:
<form method="post" action="">
{{ form }}
</form>
Or if you want custom html in each field:
<form method="post" action="">
{% for field in form %}
{{ field.label_tag }} {{ field }}
{% endfor %}
</form>
Reference:
https://docs.djangoproject.com/en/1.11/topics/forms/
i am not able to upload an image from html page but it is possible from admin page
here is my models.py:
def get_upload_file_name(instance,filename):
return "image/%s_%s"%(str(time()).replace('.','_'),filename)
class Company_Profile(models.Model):
user = models.ForeignKey(User)
name = models.CharField(_('Company Name'), max_length= 30)
logo = models.FileField(_('Company Logo'), upload_to=get_upload_file_name)
address = models.TextField(_('Contact Address'), max_length=50)
phone_no = models.IntegerField(_('Contact No'), max_length=12)
my views.py:
def company_prof(request):
if request.method == 'POST':
comp_prof = Company_Prof(request.POST, request.FILES)
if comp_prof.is_valid():
save_prof = comp_prof.save(commit=False)
save_prof.user = request.user
save_prof.save()
messages.success(request, 'Thank you for Registration')
return HttpResponseRedirect('company/'+str(save_prof.id))
else:
comp_prof =Company_Prof()
variables = RequestContext(request, {
'comp_form': Company_Prof()})
return render_to_response("comp_profile.html",
locals(),
context_instance = RequestContext(request))
my settings.py is:
MEDIA_ROOT ='G:\Mini project\Pycharm projects\project4\static/'
MEDIA_URL = ''
html page is:
<form enctype="application/x-www-form-urlencoded" class="global_form" action="" method="post"><div><div><h3>Create Account</h3>
<div id="connect_signup_box" class="connect_box_form clearfix">
<form method="POST" enctype="multipart/form-data">{% csrf_token %}
{{ comp_prof.as_p }}
<input type="submit" class="btn btn-success" value="submit">
{% if save_prof %}
<h3>The details are submitted</h3>
{% endif %}
<input type="reset" class="btn" value="cancel">
{% if value == 'cancel' %}
<h3>Canceled</h3>
{% endif %}
</form>
</div>
</div>
</div>
</form>
when i submit it says no files are chosen. but from admin page there is no problem.
help me..
I think the problem is you have nested forms, which isn't supported by browsers (Can you nest html forms?).
So I am assuming that the browser is just using the first form definition, which has the wrong enctype. Try removing the first form declaration and just keeping this one: <form method="POST" enctype="multipart/form-data">.
I am working with Django forms and for some reason, this form will not validate! It submits alright, or at least the runserver shows an http post response with code 200 (ok). For some reason though, my form will not pass the is_valid test!
views.py:
def new_show(request):
if request.method == 'POST':
img_form = ImageForm(request.POST, request.FILES)
show_form = NewShowForm(request.POST)
if show_form.is_valid():
new_Show = Show()
new_Show.title=show_form.cleaned_data['title']
new_Show.body=show_form.cleaned_data['body']
new_Show.pub_date=timezone.now()
new_Show.location=show_form.cleaned_data['location']
new_Show.time=show_form.cleaned_data['time']
new_Show.save()
if img_form.is_valid():
image=Image(image=request.FILES['imageFile'])
new_Show.image_set.add(image)
return HttpResponseRedirect(reverse('shows'))
else:
return HttpResponseRedirect(reverse('shows'))
else:
show_form = NewShowForm()
img_form = ImageForm()
return render_to_response(
'shows/new_show.html',
{'show_form': show_form, 'img_form': img_form},
context_instance=RequestContext(request)
)
Here is my template snippet:
<form action="{% url "new_show" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ show_form.non_field_errors }}</p>
<p>
<label for="title">Title:</label>
<input type="text" name="title"/>
</p>
<p>
<label for="body">Body:</label>
<textarea type="text" name="body"> </textarea>
</p>
<p>
<label for="location">Location:</label>
<input type="text" name="location"/>
</p>
<p>
<label for="time">Date:</label>
<input type="text" id="time" maxlength="25" size="25" name="time"><img src="{{ STATIC_URL }}../../static/cal.gif" width="16" height="16" border="0" alt="Pick a date">
</p>
<!-- Upload Form. Note enctype attribute! -->
{% csrf_token %}
<p>{{ img_form.non_field_errors }}</p>
<p>{{ img_form.imageFile.label_tag }}</p>
<p>
{{ img_form.imageFile.errors }}
{{ img_form.imageFile }}
</p>
<p><input type="submit" value="Add Upcoming Show"></input></p>
</form>
Here is my form Class:
class NewShowForm(forms.Form):
title=forms.CharField()
body=forms.CharField(widget=forms.TextArea)
location=forms.CharField()
time=forms.DateTimeField(required=True)
class ImageForm(forms.Form):
imageFile = forms.FileField(required=False, label='Select an Image')
Please help me!
If new_Show is a model, why not create a ModelForm instead of forms.Form?
So, instead of
class NewShowForm(forms.Form):
title=forms.CharField()
body=forms.CharField(widget=forms.TextArea)
location=forms.CharField()
time=forms.DateTimeField(required=True)
class ImageForm(forms.Form):
imageFile = forms.FileField(required=False, label='Select an Image')
why not using,
from django.forms import ModelForm
class NewShowForm(ModelForm):
class Meta:
model = NewShow
class ImageForm(ModelForm):
class Meta:
model = Image
?
Using ModelForm will ensure that form validation meets that of model. Moreover, it can cut off your code (especially line 6 to 11).
It will help to add these two lines to your view before if is_valid() to see the errors it's giving:
if request.method == 'POST':
img_form = ImageForm(request.POST, request.FILES)
show_form = NewShowForm(request.POST)
print(form.is_valid())
print(form.errors)
if show_form.is_valid():
You can paste the errors here and we can see what's the issue
Since you've put 2 Django forms together under one HTML form tag, when you submit the form on the front-end you're sending an extra field through request.POST that your NewShowForm doesn't have. If you combine both forms into a single Django form, you should be able to get this to work.