django Enter a valid date. validation error - django

My model
class Member(models.Model):
dob = models.DateField('dob')
form
class MemberForm(ModelForm):
dob = forms.DateField(required=False, input_formats='%Y-%m-%d')
class Meta:
model = Member
exclude = ('profile',)
some view code
if request.method == 'POST': # If the form has been submitted...
signup_form = SignupForm(request.POST) # A form bound to the POST data
# Create a formset from the submitted data
member_formset = MemberFormSet(request.POST, request.FILES)
# import pdb; pdb.set_trace()
if signup_form.is_valid() and member_formset.is_valid():
print 'in valid'
signup = signup_form.save(request.POST)
for form in member_formset.forms:
member = form.save(commit=False)
member.profile = signup
# import pdb; pdb.set_trace()
# print member.objects.all()
member.save()
return redirect("/main") # Redirect to a 'success' page
when m submitting the form the error message coming is
Enter a valid date.
What should i do to solve this validation .

input_formats needs to be a list, see
example:
['%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y'] # '10/25/06'
https://docs.djangoproject.com/en/dev/ref/forms/fields/#django.forms.DateField

I prefer to set **DATE_INPUT_FORMATS
in settings.py and then define the field like:
dob = forms.DateField(input_formats=settings.DATE_INPUT_FORMATS)
This more DRY than setting it on a per form field basis.
If it's a text field input, I almost always put the accepted format(s) in the field's help_text so that the user can know what format(s) is(are) accepted.

You do not need to add a new field once you already have a DateField in your Model.
You just have to set the input_formats for this field:
self.fields[ 'dob' ].input_formats = [ '%Y-%m-%d' ]
References: DateField and Format Localization

The input_formats is your friend.
If you accept javascript, then you could make the field use something like jQuery calendar (i.e. a read-only text field and clicking on it will call the jquery code and pop up the calendar widget). You can have this calendar widget as a starting point.

Related

Tango With Django - Fun With Forms URLconf Error

I am currently doing the latest tango with django course and have just about finished '8. Fun with Forms', I however cannot solve an error I am getting. The course tells us to make an add_page form and supplies us with the view and the form, all we really have to do is create the URL, I have done this however I cannot get it to recognize the URL for the add_page view.
Sorry I cannot post pictures as I do not have high enough reputation so I have given links.
This is the error I get
http://i.stack.imgur.com/UrFxv.png
Here is my code
URLS -
from django.conf.urls import patterns, url
from rango import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^about/', views.about, name="about"),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$', views.add_page, name='add_page'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),
)
VIEWS -
from django.shortcuts import render
from django.http import HttpResponse
from rango.models import Category, Page
from rango.forms import CategoryForm, PageForm
def index(request):
# Query the database for a list of ALL categories currently stored.
# Order the categories by no. likes in descending order.
# Retrieve the top 5 only - or all if less than 5.
# Place the list in our context_dict dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-views')[:5]
context_dict = {'categories': category_list, 'pages': page_list}
# Render the response and send it back!
return render(request, 'rango/index.html', context_dict)
def about(request):
message = "Rango says here is the about page. <a href='/rango/'>Index</a> "
return HttpResponse(message)
def category(request, category_name_slug):
# Create a context dictionary which we can pass to the template rendering engine.
context_dict = {'category_name_slug': category_name_slug}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
# Retrieve all of the associated pages.
# Note that filter returns >= 1 model instance.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displays the "no category" message for us.
pass
# Go render the response and return it to the client.
return render(request, 'rango/category.html', context_dict)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# Save the new category to the database.
form.save(commit=True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print form.errors
else:
# If the request was not a POST, display the form to enter details.
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'rango/add_category.html', {'form': form})
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
# probably better to use a redirect here.
return category(request, category_name_slug)
else:
print form.errors
else:
form = PageForm()
# made the change here
context_dict = {'form': form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
FORMS -
from django import forms
from rango.models import Page, Category
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="Please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
# An inline class to provide additional information on the form.
class Meta:
# Provide an association between the ModelForm and a model
model = Category
fields = ('name',)
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
# Provide an association between the ModelForm and a model
model = Page
# What fields do we want to include in our form?
# This way we don't need every field in the model present.
# Some fields may allow NULL values, so we may not want to include them...
# Here, we are hiding the foreign key.
# we can either exclude the category field from the form,
exclude = ('category',)
#or specify the fields to include (i.e. not include the category field)
#fields = ('title', 'url', 'views')
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
# If url is not empty and doesn't start with 'http://', prepend 'http://'.
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
I think that is all the code necessary however just let me know if there are another files you would like to see and I'll put them up. Any help appreciated, thanks
A simple mistake, in my browser I was doing this 'http://127.0.0.1:8000/rango/category/other-frameworks/add_page.html', however my URL Tuple was not looking for a '.html' as the end so I removed it so it looked like this 'http://127.0.0.1:8000/rango/category/other-frameworks/add_page' and that solved my problem. Thanks to sgmart.

Add data to ModelForm object before saving

Say I have a form that looks like this:
forms.py
class CreateASomethingForm(ModelForm):
class Meta:
model = Something
fields = ['field2', 'field3', 'field4']
I want the form to have these three fields. However my Somethingclass also has field1. My question is - how do I add data to field1, if I am not using the ModelForm to collect the data. I tried doing something like this, but it isn't working and I am unsure on the proper way to solve this:
views.py
def create_something_view(request):
if (request.method == 'POST'):
# Create an object of the form based on POST data
obj = CreateASomething(request.POST)
# ** Add data into the blank field1 ** (Throwing an error)
obj['field1'] = request.user
# ... validate, save, then redirect
The error I receive is:
TypeError: 'CreateAClassForm' object does not support item assignment
In Django, what is the proper way to assign data to a ModelForm object before saving?
form = CreateASomething(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.field1 = request.user
obj.save()
Sometimes, the field might be required which means you can't make it past form.is_valid(). In that case, you can pass a dict object containing all fields to the form.
if request.method == 'POST':
data = {
'fields1': request.user,
'fields2': additional_data,
}
form = CreateASomethingForm(data)
if form.is_valid():
form.commit(save)
There are two ways given by Django official
LINK : https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/
Method 1]
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
Method 2]
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
Here is a more suitable way to add data especially used during testing:
First convert an existing entry into a dictionary with the model_to_dict function
from django.forms.models import model_to_dict
...
valid_data = model_to_dict(entry)
Then add the new data into this dictionary
valid_data['finish_time'] = '18:44'
This works better than setting the value in the form
update_form.finish_time = '18:44'
Create the form with the valid data and the instance
update_form = UserEntryForm(valid_data, instance=entry)
Do any assertions you require:
self.assertTrue(update_form.is_valid())
entry = update_form.save()
self.assertEqual(
entry.status,
1
)

django prepopulate modelform - nothing happens

This must be a very simple thing however I can not seem to get through it..
I trying to build a form where the user can update a ModelForm. First he inserts a user id and afterwards I want to show him the form pre-populate with the original data so he can change only the fields that he wants.
After some the help of my friend google, stackoverflow and the django documentation, I've come to this:
views.py
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
form = TableForm(instance=user)
return render_to_response('template.html',{'form':form})
forms.py
class TableForm(forms.ModelForm):
pres_clinic = forms.ModelChoiceField(queryset=PresClinic.objects.all(),
widget=SelectWithPop(), label=ugettext("Clinic presentation"),
required=False)
MAYBECHOICES = (
('', '---------'),
(ugettext('Yes'), ugettext('Yes')),
(ugettext('No'), ugettext('No')))
bcg_scar = forms.ChoiceField(choices=MAYBECHOICES, label=ugettext(
"BCG scar"), required=False)
mantoux_register = forms.ChoiceField(choices=MAYBECHOICES,
label=ugettext("Mantoux register"), required=False)
date_diag = forms.DateField(widget=DateTimeWidget, label=ugettext(
"Diagnosis date"), required=False)
situation = forms.ModelChoiceField(queryset=Situation.objects.all(),
widget=SelectWithPop(), label=ugettext("Patient status"),
required=False)
date_situation = forms.DateField(widget=DateTimeWidget, label=ugettext(
"Date patient status"), required=False)
class Meta:
model = Table
fields = ('pres_clinic', 'bcg_scar', 'mantoux_register',
'date_diag', 'situation', 'date_situation')
def clean(self):
cleaned_data = self.cleaned_data
diag = cleaned_data.get('date_diag')
errors = []
now = datetime.date.today()
if diag is not None and diag != u'':
if diag > now:
errors.append(ugettext('The field "Diagnosis date" should be '
'smaller than the actual date'))
if errors:
raise ValidationError(errors)
return cleaned_data
template:
{{ form }} # presents the empty form and not the data from that user
The version of django is 1.4
Can anyone tell me what is wrong and why I'm not able to see the form populated?
Thank you very much
You need to define a dictionary to be used for the initial data and change from TableForm(instance=user) to TableForm(initial=dict), for example something like:
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
data = {'pres_clinic' : 'value', 'bcg_scar' : 'value', 'mantoux_register' : 'value'}
form = TableForm(initial=data)
return render_to_response('template.html',{'form':form})
I would also put the render to response out of the if statement so if the form isn't valid the page should reload and show any errors.
More information on the django docs here
I hope this helps!
You can try 'model_to_dict'
from django.forms.models import model_to_dict
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
form = TableForm(initial=model_to_dict(user))
return render_to_response('template.html',{'form':form})

autopopulate from user django

I'm trying to make a form for updating user accounts in Django that is autopopulated with the current account data for that particular user. I can do this with HTML, but would rather find a way to make it work using Django's form system. I can't use Django's built-in user management due to certain constraints and am having to construct my own. I'm lost on where to start with this.
If you're using a normal form (sublassing forms.Form), pass data in using the initial keyword argument to your form constructor:
# forms.py
class MyUserForm(forms.Form):
username = forms.CharField(...
first_name = forms.CharField(...
...
# views.py
if request.method == 'POST':
# Process form
form = MyUserForm(request.POST)
...
else:
form = MyUserForm(initial={
'username': request.user.username,
'first_name': request.user.first_name,
...
}
...
An even easier way, though, is using Django's ModelForms. Something like:
# forms.py
class MyUserForm(forms.ModelForm):
class Meta:
model = User
# views.py
if request.method == 'POST':
form = MyUserForm(request.POST, instance=request.user)
...
else:
form = MyUserForm(instance=request.user)
...
Read the forms chapter of The Django Book online, for free. Then look into initial_data passed to forms. That should get you rolling.

Possible to do with django forms?

I have a form where an administrators enters a list of comma-separated email addresses, and the form does validation on each email address before adding it to the db. I was able to do this just fine with using my own (non-django) form. I tried to migrate this over to using modelforms, but ran into a few problems. Here is the code I currently have --
# model
class EmailList(models.Model):
email = models.EmailField(blank=True)
network = models.ForeignKey(Network)
class EmailListForm(ModelForm):
class Meta:
model = EmailList
def clean_email(self):
if self.cleaned_data['email']:
valid_emails = []
for x in self.cleaned_data['email'].split(','):
x = x.strip().lower()
valid_emails.append(x)
return valid_emails
# in views
def email(request):
if request.POST.get('email'):
for email in form.cleaned_data.get('email'): ### ??
if form.is_valid(): ### ??
EmailList.objects.create(email = email, network=Network.objects.get(id=request.POST['network']))
return redirect('.')
I am having trouble because I can't call on the cleaned_data() until the form is validated, but the form will not validate as a whole (only its iterations will). Is it possible to construct this function using django's forms? If so, how would I accomplish this task? Thank you.
In this case I wouldn't use a ModelForm because they are for the case that you want to represent one Model instance by one Form. Here you want to produce multiple instances with one form. So just write a common form with a custom field (there is acutally an example just for this in the Django docs) and maybe a custom save method:
from django import forms
from django.core.validators import validate_email
class MultiEmailField(forms.Field):
def to_python(self, value):
"Normalize data to a list of strings."
# Return an empty list if no input was given.
if not value:
return []
return value.split(',')
def validate(self, value):
"Check if value consists only of valid emails."
# Use the parent's handling of required fields, etc.
super(MultiEmailField, self).validate(value)
for email in value:
validate_email(email)
class EmailListForm(forms.Form):
emails = forms.MulitEmailField()
network = forms.ModelChoiceField(queryset=Network.objects.all())
# save the emails to the db
def save(self):
for email in self.cleaned_data.get('emails'):
EmailList.objects.create(email = email,
network=self.network)
# in views
def email(request):
if request.method == 'POST':
form = EmailListForm(request.POST)
if form.is_valid():
form.save()
return redirect(...somewhere...)
else:
form = EmailListForm()
return render(request, 'some/template.html', { 'form': form }