Disable validation when calling form for the first time - django

I am struggling a bit with my Django forms. When I call my form site, always validation errors appear (this field is required). I'd prefer to see this message after clicking the submit button, if a field is not filled like a javascript function would do. In addition I'm using regex for validation, which is working fine.
I am working with CVBs. Here is some code:
models.py
class Institute(models.Model):
name = models.CharField(max_length=50)
timestamp = models.DateTimeField(auto_now_add=True)
views.py
class InstituteCreate(CreateView):
model = Institute
form_class = InstituteForm
success_url = reverse_lazy('institute_list')
forms.py
class InstituteForm(forms.ModelForm):
name= forms.CharField(error_messages={'required': 'Own Error Text'}, validators=[RegexValidator(regex='^[a-zA-ZäüößÄÜÖ]*$', message='forbidden string', code='string_invalid')])
class Meta:
model = Institute
fields = ['name']
Hope someone has an idea on how to fix it.
edit1:
my template is quite simple
{% block pagetitle %}Institutes{%endblock %}
{% block content %}
<form class="form-horizontal" name="form_group" method="post">
{% csrf_token %}
<div>
{{ form.as_p }}
</div>
<input class="btn btn-primary" type="submit" value="click me" />
</form>
{% endblock %}
and my url config:
urlpatterns = patterns('',
url(r'^institute_create/$', views.InstituteCreate.as_view(), name='institute_create'),
)
I'm new to Django development so i'll try to explain the problem more detailed:
On my website, when i open the link www.exampleurl.com/institute_create my form is shown. Then i see the field where i have to enter the name for the institute. Above this field the text "this field is required" is displayed. But i don't want to see this, until i try to submit an empty form.
When i enter some text which doesnt match and i press submit button the error text field changes its message to forbidden string as expected.

Unless you're using a POST request to your view, form validation won't be triggered. There's likely an error somewhere else in your code, however, there are couple of things about your code that you'll want to address:
Classes in Python should always begin with an upper-case letter and follow the CapWords convention:
class Institute(models.Model):
name = models.CharField(max_length=50)
# just use the built-in `auto_now_add` argument
timestamp = models.DateTimeField(auto_now_add=True)
class InstituteCreate(CreateView):
model = Institute
form_class = InstituteForm
success_url = reverse_lazy('institute_list')
class InstituteForm(forms.ModelForm):
# All Django model/form fields are required by default, so you
# can drop the `required=True` here
name= forms.CharField(validators=[RegexValidator(regex='^[a-zA-ZäüößÄÜÖ]*$',
message='forbidden string', code='string_invalid')])
class Meta:
model = Institute
fields = ['name']
Otherwise, it's impossible to tell the difference between the class definition and an instance of the class, and you're a lot less likely to run into collisions.
Just out of curiosity, are you seeing in-browser HTML5 validation errors versus errors from Django? If you can add your template code to your question it might help.

I know this is a very old question, but I don't see it answered. I am a beginner in django too and I was following the Django tutorial when I faced the same issue.
I resolved it this way:
if 'voteButton' in request.POST:
context = {
'question': question,
'error_message': "You didn't select a choice"
}
return render(request, 'polls/details.html', context)
elif:
# do something else. Display error message
voteButton is the name of the 'submit' button in your form. Hope this helps! Please do let me know if this approach is wrong.

As Brandon mentioned, your form gets validated on a POST request. So ensure that during the first visit of the page, the Form doesn't get bound to a POST request.
For example, don't do this :
def register(request):
form = RegistrationForm(request.POST)
if request.method == 'POST':
if form.is_valid():
# Do something
return render(request, 'register.html', {'form': form})
You should bind the form to a POST request only if the page is accessed via a POST request. This should help:
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# DO something
else :
form = RegistrationForm()
return render(request, 'register.html', {'form': form})

Related

Passing data to form (from POST and url)

I'm not sure how to pass data from a given object (profile) and from form (request.POST) to one model (many to many relation).
I have two models: Profile and Keyword. Users can define many profiles (for different subjects) and in each profile they can define many keywords (used later by a crawler). It is possible that the same keyword is in many profiles, and one profile can have many keywords.
Now, I have a view adding new profile to user, and in next step I want to add view adding keyword/keywords to this particular profile.
I'm passing a parameter foreign key - profile_id - via url, and I have build form from my model Keyword. Now I have problem with passing both of them to my function.
models.py
class Profiles (models.Model):
id_profile = models.AutoField(primary_key=True)
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=45)
description = models.TextField(max_length=120, default=' ')
class Keywords (models.Model):
id_keyword = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
id_profile = models.ManyToManyField(Profiles)
template
<button class="btn btn-outline-danger" type="submit"> new keyword </button>
urls.py
path('profile_detail/<int:pk>/', users_view.ProfileDetailView.as_view(), name = 'profile_detail'),
path('new_keyword/<profile_id>/', users_view.NewKeyword, name = 'new_keyword'),
views.py
def newKeyword(request):
form = NewKeyword(request.POST)
if request.method == 'POST':
form.is_valid()
form.save()
return redirect('profile')
return render(request, 'users/new_keyword.html', {'form': form})
Now I have
__init__() got an unexpected keyword argument 'profile_id'
I understand that I have to somehow overwrite init() to accept profile_id, but I'm not sure how.
ok, thank you for you answer. I have changed my code, but now I have different problem:The Keywords could not be created because the data didn't validate.
def newKeyword(request):
context = {}
context['id_profile'] = request.POST.get('id_profile', None)
form = NewKeyword(request.POST or None)
if request.method == 'POST':
form.is_valid()
obj = form.save(commit=False)
obj.save()
obj.id_profile.add(context['id_profile'])
obj.save()
return redirect('profile')
return render(request, 'users/new_keyword.html', {'form': form})
and template in previous page:
<form method="POST" name="newkeyword" value='keyword'>
<fieldset class="form-group">
<legend class="border-bottom mb-4"> New keyword </legend>
{{ form | crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-danger" type="submit">create</button>
</div>
</form>
Looks like after clicking a button on page profile (in order to go to view: creating keyword) I use method POST to send parameter, hence my 'If statement' runs...
You are trying to retrieve GET data.
def newKeyword(request, profile_id):
and you can retrieve that parameter with this way but for POST data,
you can use;
request.GET.get('profile_id') # GET method
request.POST.get('profile_id') # POST method
and you don't need to edit url for this.
related question:
Passing variable from django template to view

Bind dynamic choices to ModelForm in Django

I'm trying to bind a dynamic list of choices to a ModelForm. The form is rendered correctly. However, when using the form with a POST Request, I get an empty form back. My goal is to save that form into the database (form.save()). Any help would be much appreciated.
Model
I'm using a multiple choice select field ( https://github.com/goinnn/django-multiselectfield )
from django.db import models
from multiselectfield import MultiSelectField
class VizInfoModel(models.Model):
tog = MultiSelectField()
vis = MultiSelectField()
Forms
class VizInfoForm(forms.ModelForm):
class Meta:
model = VizInfoModel
fields = '__all__'
def __init__(self,choice,*args,**kwargs):
super(VizInfoForm, self).__init__(*args,**kwargs)
self.fields['tog'].choices = choice
self.fields['vis'].choices = choice
View
Choices are passed from the view when instantiating the form.
def viz_details(request):
options = []
headers = request.session['headers']
for header in headers :
options.append((header, header))
if request.method == 'POST':
form = VizInfoForm(options, request.POST)
#doesnt' get into the if statement since form is empty!
#choices are not bounded to the model although the form is perfectly rendered
if form.is_valid():
form.save()
return HttpResponseRedirect('/upload')
else:
#this works just fine
form = VizInfoForm(options)
return render(request, 'uploads/details.html', {'form': form})
Template
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>Choose variables to toggle between</p>
{{ form.tog }}
<br></br>
<p>Choose variable to be visualized</p>
{{ form.vis }}
<br></br>
<button type="submit">Submit</button>
</form>
You're saying Django doesn't get into your if request.method == 'POST' block.
This tells us that you're not sending your request through the POST method. Your template probably has an error in it, maybe you haven't specified the method on your form, or you made your button to just be a link instead of a submit ?
Show your template so we can say more, unless this was enough to solve your question !

Django template isn't rendering dynamic form errors

I have a Django 1.8 form that contains a paragraph tag that renders either some feedback or a question submitted by a user. It also contains a textarea input 'response_text' and a pair of radio buttons 'close_issue'. This response input can be used to send an optional response to the user. If the user submitted some feedback, the admin should be able to click the 'close issue' radio button and submit the form with no response. However, if the textarea input contains a question, then the form should render an error telling the admin that he/she can't submit the form without typing an answer into the response input. The problem I'm having is that I can't get the form to cause the template to render an error message if the user submitted a question but the admin didn't type in a response. My view, model, form, and template are shown below. forms.py shows all the ways (all commented out) I have tried to make the response input field required if the user submitted a question so that the template will display an error. I also tried overriding the default 'clean' method with one that would raise a ValidationError if the user submitted a question and the response input is blank but that didn't work either. Can anyone tell me what I'm doing wrong?
Thanks.
# view.py
def review_feedback_or_question(request, template, *args, **kwargs):
fqid = kwargs['fqid']## Heading ##
submission = FeedbackQuestion.objects.get(pk=fqid)
if request.method == 'POST':
form = FeedbackQuestionResponseForm(request.POST, submission=submission)
if form.is_valid():
# process the form
return redirect('review-feedback-or-question-queue')
else:
pass
form = FeedbackQuestionResponseForm(submission=submission)
context = {'form': form, 'submission': submission,}
return render(request, template, context)
# models.py
class FeedbackQuestion(models.Model):
SELECT = ''
FEEDBACK = 'feedback'
QUESTION = 'question'
SUBMISSION_TYPE_CHOICES = (
(SELECT , '-- Select --'),
(FEEDBACK, 'Feedback'),
(QUESTION, 'Question'),
)
user = models.ForeignKey(User, related_name="user")
submission_type = models.CharField(max_length=8,
choices=SUBMISSION_TYPE_CHOICES,
default=SELECT)
submission_text = models.TextField()
date_submitted = models.DateTimeField(auto_now_add=True)
response_text = models.TextField()
respondent = models.ForeignKey(User, related_name='respondent')
date_responded = models.DateTimeField(auto_now=True)
issue_closed = models.BooleanField(default=False)
class Meta:
db_table = 'feedback_question'
# forms.py
class FeedbackQuestionResponseForm(forms.Form):
TRUE = 1
FALSE = 0
BLANK = ''
CHOICES = ( (TRUE, 'Yes'), (FALSE, 'No') )
response_text = forms.CharField(
required=False,
label='',
widget=forms.Textarea(attrs={'placeholder': 'Enter response...'}))
close_issue = forms.TypedChoiceField(
choices=CHOICES,
label='Close this issue?',
widget=forms.RadioSelect(renderer=HorizontalRadioRenderer),
coerce=int)
def __init__(self, *args, **kwargs):
if 'submission' in kwargs:
submission = kwargs.pop('submission')
if submission.submission_type == 'question':
# NONE OF THESE WORKED!
#self.fields.get('response_text').required = True
#self.declared_fields['response_text'].required = self.TRUE
#self.declared_fields['response_text'].required = self.TRUE
#self.declared_fields['response_text'].required = True
#self._errors['response_text'] = "You must enter a response"
pass
super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
# template.html
<p>{{ submission.submission_text }}</p>
<form action="" method="post">{% csrf_token %}
{{ form.non_field_errors }}
{% if form.errors %}
{% if form.errors.items|length == 1 %}
Please correct the error below.
{% else %}
Please correct the errors below.
{% endif %}
</p>
{% endif %}
{{ form.response_text.errors }}
{{ form.response_text.label_tag }} {{ form.response_text }}
{{ form.close_issue.errors }}
{{ form.close_issue }} {{ form.close_issue.label_tag }}
<input type="submit" value="Submit" class="" />
</form>
You're not passing submission into the form when you instantiate it on POST, so the required attribute is never being set.
Daniel Roseman was correct in that I need to pass 'submission' into the form when I instantiate the form on POST. But there were still two other problems. First, I need to instantiate the form inside the else block. If this isn't done and the form doesn't validate, then you're passing an unbound form back to the viewer and any errors won't be displayed. Also, it isn't necessary to pass 'submission' to the form when you instantiate it here:
...
else:
form = FeedbackQuestionResponseForm()
context = {...}
...
The next problem was that the order of my statements inside the init method was incorrect. It appears that I needed to execute 'super()' before trying to reference the 'response_text' field. I'll need to locate and study this method in the Django source code to understand exactly why. In any case, this works:
def __init__(self, *args, **kwargs):
if 'submission' in kwargs:
submission = kwargs.pop('submission')
else:
submission = False
super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
if submission:
if submission.submission_type == 'question':
self.fields['response_text'].required = True
else:
self.fields['response_text'].required = False
When the above changes are implemented, the form will make the response_text field required if the user submits a question and an error will be displayed if the admin doesn't enter a response before submitting the form. Many thanks again to Daniel for getting me back on track towards finding a solution.

Django - Form element's default value error

there are two links in one page[admin page]. both goes to same form page[ Add Post ]. in admin page ; you can click to 'new post' link or you can type your title in a textbox which is connected to same page[Add Post]. in that page ; i have a form which have a checkbox field.
isdraft = forms.BooleanField(required=False,initial=True)
as you can see ; i set the field's default value True. if i click the 'new post' at admin page ; to come that form page ; it works great. checkbox comes to me as True. but if i use other way [ typing title in textbox ] checkbox comes to me as False. i couldn't figure that out.
edit : i think the question is complicated. not clear. if any additional data needed ; i can add it.
edit :
admin.html :
<h1>PostsNew Post</h1> #this works!
<form action="{% url add_post %}" method="POST">{% csrf_token %}
{{ form.title }} <!-- this is textbox -->
{{ form.isdraft.as_hidden }} <!-- when i add this line form works correctly. but i get 'please fill all fields' warning when redirected to add_post page. -->
</form>
edit2 :
add_post view:
#login_required(login_url='/login/')
def add_post(request):
template_name = 'add.html'
owner = request.user
if request.method == "POST":
form = addForm(request.POST)
if form.is_valid():
titleform = form.cleaned_data['title']
bodyform = form.cleaned_data['body']
checkform = form.cleaned_data['isdraft']
n = Post(title=titleform, body=bodyform, isdraft=checkform, owner=owner)
n.save()
messages.add_message(request, messages.SUCCESS,
'New post created successfully!')
return HttpResponseRedirect('/admin/post/add/')
else:
messages.add_message(request, messages.WARNING,
'Please fill in all fields!')
else:
form = addForm()
return render_to_response(template_name, {'form': form, 'owner':owner,},context_instance=RequestContext(request))`
admin view :
#login_required(login_url='/login/')
def admin_view(request):
if request.session.get('loggedin') == "djangoo":
form = newDraft() # textbox in admin page
return render_to_response('admin.html', {'form':form },context_instance=RequestContext(request))
else:
return HttpResponseRedirect('/login/')
addForm :
class addForm(forms.Form):
title = forms.CharField(max_length=100,
widget=forms.TextInput(attrs={'placeholder':'Title here',}))
body = forms.CharField(widget=forms.Textarea(
attrs={'placeholder':'Write post here','rows':'25','cols':'90',}))
isdraft = forms.BooleanField(required=False,initial=True)
initial only works when the form is unbound.
When you click the new post link, you are doing a get request on the page, so the form is unbound and the initial value is used.
When you enter a title and submit, I assume you are doing a post request on the page. Therefore the form is bound, and the initial value will not be used.
I'm afraid I don't understand the question completely, and you haven't show much code, so I can't suggest any work arounds for you. Hope you get it working.
Update following edits to your question
When the data comes from the add_post view, don't create a bound form, because then the data will be validated and you'll get the error messages.
Instead, fetch the title from the post data, and use that to create an initial dictionary to instantiate your addForm with.
You need a way to tell whether the post request came from the admin or add post view. You could do this by adding another hidden field to the addForm.
action = forms.CharField(widget=forms.HiddenInput, initial="addform")
Then change your add_post view to something like:
if request.method == 'POST':
if request.POST.get('action') == 'addform':
form = addForm(initial={'title': request.POST.get('title'), 'isdraft': True})
else:
# your existing code for handling a request post

Hidden validation form - Django

I'm having really hard time trying to make this code work. I'm using Python 2.7 and Django 1.3
When I try to submit the form, it leads me to the error page, like the form has something wrong.
I have a model class with an image field:
class Livro (models.Model):
Titulo = models.CharField(max_length=200)
Autor = models.CharField(max_length=200)
Genero = models.CharField(max_length=100)
Editora = models.CharField(max_length=200)
Capa = models.ImageField(upload_to='media', blank=True, null=True)
ISBN = models.CharField(max_length=200)
Serie = models.CharField(max_length=200)
Data = models.DateField()
Tipocapa = models.CharField(max_length=100)
Lingua = models.ForeignKey(PropObra,'Lingua', related_name="lingualivro")
def __unicode__(self):
return self.Titulo
This is the view I have implemented:
def salvalivro(request):
if request.method == 'POST':
form = LivroForm(request.POST, request.FILES)
if form.is_valid():
form = LivroForm()
if not form.is_valid():
return HttpResponseRedirect('/erro/')
return render_to_response('salvalivro.html', {'form': form,}, context_instance=RequestContext(request))
And this is the code I have inside the template:
<form enctype="multipart/form-data" method="POST" action="/salvalivro/" >{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Salvar" />
</form>
Maybe the error is in front of my nose, but I've been working on this for about three days and had no result. I've read Django's documentation and many other questions around StackOverflow, but still got nothing. I really need some help...
Your view code doesn't make a whole lot of sense. You're creating a new instance of the form after checking that the previously created one is valid, then redirecting to an error page if it's not. So, your code looks to me like it's working as expected as described in your question.
Try this view instead (assumes Django 1.3):
def salvalivro(request):
form = LivroForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
form.save() #or whatever else you need
return render(request, 'salvalivro.html', {'form': form})
Your view is very odd. If it's a post, you instantiate the form using the post data. Then, you check it's valid: then you re-instantiate the form with no data and check if it isn't valid! Of course, at that point it can't ever be valid, because the second instantiation has no data. So, naturally, it always redirects - but again, because you're redirecting to a different view, you'll never see the actual error messages generated by the form.
You should look more closely at the standard documentation on using a form in a view - it has the exact pattern you should follow.