mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
unicode: Merged from trunk up to [5213].
git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5214 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
bc044651aa
commit
28f66bb097
1
AUTHORS
1
AUTHORS
@ -78,6 +78,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
flavio.curella@gmail.com
|
flavio.curella@gmail.com
|
||||||
Jure Cuhalev <gandalf@owca.info>
|
Jure Cuhalev <gandalf@owca.info>
|
||||||
dackze+django@gmail.com
|
dackze+django@gmail.com
|
||||||
|
David Danier <goliath.mailinglist@gmx.de>
|
||||||
Dirk Datzert <dummy@habmalnefrage.de>
|
Dirk Datzert <dummy@habmalnefrage.de>
|
||||||
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
|
Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/>
|
||||||
dave@thebarproject.com
|
dave@thebarproject.com
|
||||||
|
Binary file not shown.
@ -1344,7 +1344,7 @@ msgstr "四月"
|
|||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "may"
|
msgid "may"
|
||||||
msgstr "三月"
|
msgstr "五月"
|
||||||
|
|
||||||
#: utils/dates.py:19
|
#: utils/dates.py:19
|
||||||
msgid "jun"
|
msgid "jun"
|
||||||
|
Binary file not shown.
@ -46,7 +46,7 @@ msgstr "清除全部"
|
|||||||
#: contrib/admin/media/js/dateparse.js:32
|
#: contrib/admin/media/js/dateparse.js:32
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/calendar.js:24
|
||||||
msgid "January February March April May June July August September October November December"
|
msgid "January February March April May June July August September October November December"
|
||||||
msgstr "一月 二月 三月 四月 五月 六月 六月 七月 八月 九月 十月 十一月 十二月"
|
msgstr "一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:33
|
#: contrib/admin/media/js/dateparse.js:33
|
||||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||||
|
@ -41,7 +41,7 @@ class ISIdNumberField(RegexField):
|
|||||||
method is modulo 11.
|
method is modulo 11.
|
||||||
"""
|
"""
|
||||||
check = [3, 2, 7, 6, 5, 4, 3, 2, 1, 0]
|
check = [3, 2, 7, 6, 5, 4, 3, 2, 1, 0]
|
||||||
return sum(int(value[i]) * check[i] for i in range(10)) % 11 == 0
|
return sum([int(value[i]) * check[i] for i in range(10)]) % 11 == 0
|
||||||
|
|
||||||
def _format(self, value):
|
def _format(self, value):
|
||||||
"""
|
"""
|
||||||
|
@ -59,8 +59,11 @@ def words(count, common=True):
|
|||||||
word_list = []
|
word_list = []
|
||||||
c = len(word_list)
|
c = len(word_list)
|
||||||
if count > c:
|
if count > c:
|
||||||
count = min(count - c, len(WORDS))
|
count -= c
|
||||||
word_list += random.sample(WORDS, count - c)
|
while count > 0:
|
||||||
|
c = min(count, len(WORDS))
|
||||||
|
count -= c
|
||||||
|
word_list += random.sample(WORDS, c)
|
||||||
else:
|
else:
|
||||||
word_list = word_list[:count]
|
word_list = word_list[:count]
|
||||||
return ' '.join(word_list)
|
return ' '.join(word_list)
|
||||||
|
@ -233,7 +233,7 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD('%s_%s_seq' % (model._meta.db_table, f.column)),
|
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name(f.column)),
|
style.SQL_FIELD(quote_name(f.column)),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
@ -242,7 +242,7 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
for f in model._meta.many_to_many:
|
for f in model._meta.many_to_many:
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()),
|
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name('id')),
|
style.SQL_FIELD(quote_name('id')),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
|
@ -184,7 +184,7 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD('%s_%s_seq' % (model._meta.db_table, f.column)),
|
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name(f.column)),
|
style.SQL_FIELD(quote_name(f.column)),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
@ -193,7 +193,7 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
for f in model._meta.many_to_many:
|
for f in model._meta.many_to_many:
|
||||||
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
output.append("%s setval('%s', (%s max(%s) %s %s));" % \
|
||||||
(style.SQL_KEYWORD('SELECT'),
|
(style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()),
|
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())),
|
||||||
style.SQL_KEYWORD('SELECT'),
|
style.SQL_KEYWORD('SELECT'),
|
||||||
style.SQL_FIELD(quote_name('id')),
|
style.SQL_FIELD(quote_name('id')),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
|
@ -108,6 +108,10 @@ class QueryDict(MultiValueDict):
|
|||||||
self._assert_mutable()
|
self._assert_mutable()
|
||||||
MultiValueDict.__setitem__(self, key, value)
|
MultiValueDict.__setitem__(self, key, value)
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
self._assert_mutable()
|
||||||
|
super(QueryDict, self).__delitem__(key)
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
return str_to_unicode(MultiValueDict.get(self, key, default), self.encoding)
|
return str_to_unicode(MultiValueDict.get(self, key, default), self.encoding)
|
||||||
|
|
||||||
|
@ -255,6 +255,8 @@ class BoundField(StrAndUnicode):
|
|||||||
attrs['id'] = auto_id
|
attrs['id'] = auto_id
|
||||||
if not self.form.is_bound:
|
if not self.form.is_bound:
|
||||||
data = self.form.initial.get(self.name, self.field.initial)
|
data = self.form.initial.get(self.name, self.field.initial)
|
||||||
|
if callable(data):
|
||||||
|
data = data()
|
||||||
else:
|
else:
|
||||||
data = self.data
|
data = self.data
|
||||||
return widget.render(self.html_name, data, attrs=attrs)
|
return widget.render(self.html_name, data, attrs=attrs)
|
||||||
|
@ -12,17 +12,7 @@ from widgets import Select, SelectMultiple, MultipleHiddenInput
|
|||||||
__all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
|
__all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
|
||||||
'ModelChoiceField', 'ModelMultipleChoiceField')
|
'ModelChoiceField', 'ModelMultipleChoiceField')
|
||||||
|
|
||||||
def model_save(self, commit=True):
|
def save_instance(form, instance, fields=None, fail_message='saved', commit=True):
|
||||||
"""
|
|
||||||
Creates and returns model instance according to self.clean_data.
|
|
||||||
|
|
||||||
This method is created for any form_for_model Form.
|
|
||||||
"""
|
|
||||||
if self.errors:
|
|
||||||
raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name)
|
|
||||||
return save_instance(self, self._model(), commit)
|
|
||||||
|
|
||||||
def save_instance(form, instance, commit=True):
|
|
||||||
"""
|
"""
|
||||||
Saves bound Form ``form``'s clean_data into model instance ``instance``.
|
Saves bound Form ``form``'s clean_data into model instance ``instance``.
|
||||||
|
|
||||||
@ -33,15 +23,19 @@ def save_instance(form, instance, commit=True):
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
opts = instance.__class__._meta
|
opts = instance.__class__._meta
|
||||||
if form.errors:
|
if form.errors:
|
||||||
raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)
|
raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message))
|
||||||
clean_data = form.clean_data
|
clean_data = form.clean_data
|
||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data:
|
if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data:
|
||||||
continue
|
continue
|
||||||
|
if fields and f.name not in fields:
|
||||||
|
continue
|
||||||
setattr(instance, f.name, clean_data[f.name])
|
setattr(instance, f.name, clean_data[f.name])
|
||||||
if commit:
|
if commit:
|
||||||
instance.save()
|
instance.save()
|
||||||
for f in opts.many_to_many:
|
for f in opts.many_to_many:
|
||||||
|
if fields and f.name not in fields:
|
||||||
|
continue
|
||||||
if f.name in clean_data:
|
if f.name in clean_data:
|
||||||
setattr(instance, f.attname, clean_data[f.name])
|
setattr(instance, f.attname, clean_data[f.name])
|
||||||
# GOTCHA: If many-to-many data is given and commit=False, the many-to-many
|
# GOTCHA: If many-to-many data is given and commit=False, the many-to-many
|
||||||
@ -50,13 +44,19 @@ def save_instance(form, instance, commit=True):
|
|||||||
# exception in that case.
|
# exception in that case.
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def make_instance_save(instance):
|
def make_model_save(model, fields, fail_message):
|
||||||
"Returns the save() method for a form_for_instance Form."
|
"Returns the save() method for a Form."
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
return save_instance(self, instance, commit)
|
return save_instance(self, model(), fields, fail_message, commit)
|
||||||
return save
|
return save
|
||||||
|
|
||||||
def form_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formfield()):
|
def make_instance_save(instance, fields, fail_message):
|
||||||
|
"Returns the save() method for a Form."
|
||||||
|
def save(self, commit=True):
|
||||||
|
return save_instance(self, instance, fields, fail_message, commit)
|
||||||
|
return save
|
||||||
|
|
||||||
|
def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda f: f.formfield()):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for the given Django model class.
|
Returns a Form class for the given Django model class.
|
||||||
|
|
||||||
@ -71,13 +71,16 @@ def form_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formfiel
|
|||||||
for f in opts.fields + opts.many_to_many:
|
for f in opts.fields + opts.many_to_many:
|
||||||
if not f.editable:
|
if not f.editable:
|
||||||
continue
|
continue
|
||||||
|
if fields and not f.name in fields:
|
||||||
|
continue
|
||||||
formfield = formfield_callback(f)
|
formfield = formfield_callback(f)
|
||||||
if formfield:
|
if formfield:
|
||||||
field_list.append((f.name, formfield))
|
field_list.append((f.name, formfield))
|
||||||
fields = SortedDictFromList(field_list)
|
base_fields = SortedDictFromList(field_list)
|
||||||
return type(opts.object_name + 'Form', (form,), {'base_fields': fields, '_model': model, 'save': model_save})
|
return type(opts.object_name + 'Form', (form,),
|
||||||
|
{'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')})
|
||||||
|
|
||||||
def form_for_instance(instance, form=BaseForm, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
|
def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for the given Django model instance.
|
Returns a Form class for the given Django model instance.
|
||||||
|
|
||||||
@ -94,13 +97,15 @@ def form_for_instance(instance, form=BaseForm, formfield_callback=lambda f, **kw
|
|||||||
for f in opts.fields + opts.many_to_many:
|
for f in opts.fields + opts.many_to_many:
|
||||||
if not f.editable:
|
if not f.editable:
|
||||||
continue
|
continue
|
||||||
|
if fields and not f.name in fields:
|
||||||
|
continue
|
||||||
current_value = f.value_from_object(instance)
|
current_value = f.value_from_object(instance)
|
||||||
formfield = formfield_callback(f, initial=current_value)
|
formfield = formfield_callback(f, initial=current_value)
|
||||||
if formfield:
|
if formfield:
|
||||||
field_list.append((f.name, formfield))
|
field_list.append((f.name, formfield))
|
||||||
fields = SortedDictFromList(field_list)
|
base_fields = SortedDictFromList(field_list)
|
||||||
return type(opts.object_name + 'InstanceForm', (form,),
|
return type(opts.object_name + 'InstanceForm', (form,),
|
||||||
{'base_fields': fields, '_model': model, 'save': make_instance_save(instance)})
|
{'base_fields': base_fields, '_model': model, 'save': make_instance_save(instance, fields, 'changed')})
|
||||||
|
|
||||||
def form_for_fields(field_list):
|
def form_for_fields(field_list):
|
||||||
"Returns a Form class for the given list of Django database field instances."
|
"Returns a Form class for the given list of Django database field instances."
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import re, doctest, unittest
|
import re, doctest, unittest
|
||||||
|
import sys
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.core import management, mail
|
from django.core import management, mail
|
||||||
@ -46,15 +47,15 @@ class TestCase(unittest.TestCase):
|
|||||||
management.load_data(self.fixtures, verbosity=0)
|
management.load_data(self.fixtures, verbosity=0)
|
||||||
mail.outbox = []
|
mail.outbox = []
|
||||||
|
|
||||||
def run(self, result=None):
|
def __call__(self, result=None):
|
||||||
"""Wrapper around default run method to perform common Django test set up.
|
"""
|
||||||
This means that user-defined Test Cases aren't required to include a call
|
Wrapper around default __call__ method to perform common Django test
|
||||||
to super().setUp().
|
set up. This means that user-defined Test Cases aren't required to
|
||||||
|
include a call to super().setUp().
|
||||||
"""
|
"""
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
self._pre_setup()
|
self._pre_setup()
|
||||||
super(TestCase, self).run(result)
|
super(TestCase, self).__call__(result)
|
||||||
|
|
||||||
def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200):
|
def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200):
|
||||||
"""Assert that a response redirected to a specific URL, and that the
|
"""Assert that a response redirected to a specific URL, and that the
|
||||||
@ -108,7 +109,7 @@ class TestCase(unittest.TestCase):
|
|||||||
for err in errors:
|
for err in errors:
|
||||||
if field:
|
if field:
|
||||||
if field in context[form].errors:
|
if field in context[form].errors:
|
||||||
self.assertTrue(err in context[form].errors[field],
|
self.failUnless(err in context[form].errors[field],
|
||||||
"The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" %
|
"The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" %
|
||||||
(field, form, i, err, list(context[form].errors[field])))
|
(field, form, i, err, list(context[form].errors[field])))
|
||||||
elif field in context[form].fields:
|
elif field in context[form].fields:
|
||||||
@ -117,7 +118,7 @@ class TestCase(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field))
|
self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field))
|
||||||
else:
|
else:
|
||||||
self.assertTrue(err in context[form].non_field_errors(),
|
self.failUnless(err in context[form].non_field_errors(),
|
||||||
"The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" %
|
"The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" %
|
||||||
(form, i, err, list(context[form].non_field_errors())))
|
(form, i, err, list(context[form].non_field_errors())))
|
||||||
if not found_form:
|
if not found_form:
|
||||||
@ -127,7 +128,7 @@ class TestCase(unittest.TestCase):
|
|||||||
"Assert that the template with the provided name was used in rendering the response"
|
"Assert that the template with the provided name was used in rendering the response"
|
||||||
if isinstance(response.template, list):
|
if isinstance(response.template, list):
|
||||||
template_names = [t.name for t in response.template]
|
template_names = [t.name for t in response.template]
|
||||||
self.assertTrue(template_name in template_names,
|
self.failUnless(template_name in template_names,
|
||||||
u"Template '%s' was not one of the templates used to render the response. Templates used: %s" %
|
u"Template '%s' was not one of the templates used to render the response. Templates used: %s" %
|
||||||
(template_name, u', '.join(template_names)))
|
(template_name, u', '.join(template_names)))
|
||||||
elif response.template:
|
elif response.template:
|
||||||
@ -140,7 +141,7 @@ class TestCase(unittest.TestCase):
|
|||||||
def assertTemplateNotUsed(self, response, template_name):
|
def assertTemplateNotUsed(self, response, template_name):
|
||||||
"Assert that the template with the provided name was NOT used in rendering the response"
|
"Assert that the template with the provided name was NOT used in rendering the response"
|
||||||
if isinstance(response.template, list):
|
if isinstance(response.template, list):
|
||||||
self.assertFalse(template_name in [t.name for t in response.template],
|
self.failIf(template_name in [t.name for t in response.template],
|
||||||
u"Template '%s' was used unexpectedly in rendering the response" % template_name)
|
u"Template '%s' was used unexpectedly in rendering the response" % template_name)
|
||||||
elif response.template:
|
elif response.template:
|
||||||
self.assertNotEqual(template_name, response.template.name,
|
self.assertNotEqual(template_name, response.template.name,
|
||||||
|
@ -236,7 +236,7 @@ To pluralize, specify both the singular and plural forms with the
|
|||||||
``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and
|
``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and
|
||||||
``{% endblocktrans %}``. Example::
|
``{% endblocktrans %}``. Example::
|
||||||
|
|
||||||
{% blocktrans count list|count as counter %}
|
{% blocktrans count list|length as counter %}
|
||||||
There is only one {{ name }} object.
|
There is only one {{ name }} object.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
There are {{ counter }} {{ name }} objects.
|
There are {{ counter }} {{ name }} objects.
|
||||||
|
@ -83,7 +83,7 @@ If you installed Django using ``setup.py install``, uninstalling
|
|||||||
is as simple as deleting the ``django`` directory from your Python
|
is as simple as deleting the ``django`` directory from your Python
|
||||||
``site-packages``.
|
``site-packages``.
|
||||||
|
|
||||||
If you installed Django from a Python Egg, remove the Django ``.egg` file,
|
If you installed Django from a Python Egg, remove the Django ``.egg`` file,
|
||||||
and remove the reference to the egg in the file named ``easy-install.pth``.
|
and remove the reference to the egg in the file named ``easy-install.pth``.
|
||||||
This file should also be located in your ``site-packages`` directory.
|
This file should also be located in your ``site-packages`` directory.
|
||||||
|
|
||||||
|
@ -870,6 +870,308 @@ custom ``Field`` classes. To do this, just create a subclass of
|
|||||||
mentioned above (``required``, ``label``, ``initial``, ``widget``,
|
mentioned above (``required``, ``label``, ``initial``, ``widget``,
|
||||||
``help_text``).
|
``help_text``).
|
||||||
|
|
||||||
|
Generating forms for models
|
||||||
|
===========================
|
||||||
|
|
||||||
|
If you're building a database-driven app, chances are you'll have forms that
|
||||||
|
map closely to Django models. For instance, you might have a ``BlogComment``
|
||||||
|
model, and you want to create a form that lets people submit comments. In this
|
||||||
|
case, it would be redundant to define the field types in your form, because
|
||||||
|
you've already defined the fields in your model.
|
||||||
|
|
||||||
|
For this reason, Django provides a few helper functions that let you create a
|
||||||
|
``Form`` class from a Django model.
|
||||||
|
|
||||||
|
``form_for_model()``
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The method ``django.newforms.form_for_model()`` creates a form based on the
|
||||||
|
definition of a specific model. Pass it the model class, and it will return a
|
||||||
|
``Form`` class that contains a form field for each model field.
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
|
>>> from django.newforms import form_for_model
|
||||||
|
|
||||||
|
# Create the form class.
|
||||||
|
>>> ArticleForm = form_for_model(Article)
|
||||||
|
|
||||||
|
# Create an empty form instance.
|
||||||
|
>>> f = ArticleForm()
|
||||||
|
|
||||||
|
It bears repeating that ``form_for_model()`` takes the model *class*, not a
|
||||||
|
model instance, and it returns a ``Form`` *class*, not a ``Form`` instance.
|
||||||
|
|
||||||
|
Field types
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
The generated ``Form`` class will have a form field for every model field. Each
|
||||||
|
model field has a corresponding default form field. For example, a
|
||||||
|
``CharField`` on a model is represented as a ``CharField`` on a form. A
|
||||||
|
model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
|
||||||
|
the full list of conversions:
|
||||||
|
|
||||||
|
=============================== ========================================
|
||||||
|
Model field Form field
|
||||||
|
=============================== ========================================
|
||||||
|
``AutoField`` Not represented in the form
|
||||||
|
``BooleanField`` ``BooleanField``
|
||||||
|
``CharField`` ``CharField`` with ``max_length`` set to
|
||||||
|
the model field's ``maxlength``
|
||||||
|
``CommaSeparatedIntegerField`` ``CharField``
|
||||||
|
``DateField`` ``DateField``
|
||||||
|
``DateTimeField`` ``DateTimeField``
|
||||||
|
``EmailField`` ``EmailField``
|
||||||
|
``FileField`` ``CharField``
|
||||||
|
``FilePathField`` ``CharField``
|
||||||
|
``FloatField`` ``CharField``
|
||||||
|
``ForeignKey`` ``ModelChoiceField`` (see below)
|
||||||
|
``ImageField`` ``CharField``
|
||||||
|
``IntegerField`` ``IntegerField``
|
||||||
|
``IPAddressField`` ``CharField``
|
||||||
|
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
|
||||||
|
below)
|
||||||
|
``NullBooleanField`` ``CharField``
|
||||||
|
``PhoneNumberField`` ``USPhoneNumberField``
|
||||||
|
(from ``django.contrib.localflavor.us``)
|
||||||
|
``PositiveIntegerField`` ``IntegerField``
|
||||||
|
``PositiveSmallIntegerField`` ``IntegerField``
|
||||||
|
``SlugField`` ``CharField``
|
||||||
|
``SmallIntegerField`` ``IntegerField``
|
||||||
|
``TextField`` ``CharField`` with ``widget=Textarea``
|
||||||
|
``TimeField`` ``TimeField``
|
||||||
|
``URLField`` ``URLField`` with ``verify_exists`` set
|
||||||
|
to the model field's ``verify_exists``
|
||||||
|
``USStateField`` ``CharField`` with
|
||||||
|
``widget=USStateSelect``
|
||||||
|
(``USStateSelect`` is from
|
||||||
|
``django.contrib.localflavor.us``)
|
||||||
|
``XMLField`` ``CharField`` with ``widget=Textarea``
|
||||||
|
=============================== ========================================
|
||||||
|
|
||||||
|
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
|
||||||
|
types are special cases:
|
||||||
|
|
||||||
|
* ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
|
||||||
|
which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
|
||||||
|
|
||||||
|
* ``ManyToManyField`` is represented by
|
||||||
|
``django.newforms.ModelMultipleChoiceField``, which is a
|
||||||
|
``MultipleChoiceField`` whose choices are a model ``QuerySet``.
|
||||||
|
|
||||||
|
In addition, each generated form field has attributes set as follows:
|
||||||
|
|
||||||
|
* If the model field has ``blank=True``, then ``required`` is set to
|
||||||
|
``False`` on the form field. Otherwise, ``required=True``.
|
||||||
|
|
||||||
|
* The form field's ``label`` is set to the ``verbose_name`` of the model
|
||||||
|
field, with the first character capitalized.
|
||||||
|
|
||||||
|
* The form field's ``help_text`` is set to the ``help_text`` of the model
|
||||||
|
field.
|
||||||
|
|
||||||
|
* If the model field has ``choices`` set, then the form field's ``widget``
|
||||||
|
will be set to ``Select``, with choices coming from the model field's
|
||||||
|
``choices``.
|
||||||
|
|
||||||
|
Finally, note that you can override the form field used for a given model
|
||||||
|
field. See "Overriding the default field types" below.
|
||||||
|
|
||||||
|
A full example
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Consider this set of models::
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
TITLE_CHOICES = (
|
||||||
|
('MR', 'Mr.'),
|
||||||
|
('MRS', 'Mrs.'),
|
||||||
|
('MS', 'Ms.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Author(models.Model):
|
||||||
|
name = models.CharField(maxlength=100)
|
||||||
|
title = models.CharField(maxlength=3, choices=TITLE_CHOICES)
|
||||||
|
birth_date = models.DateField(blank=True, null=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Book(models.Model):
|
||||||
|
name = models.CharField(maxlength=100)
|
||||||
|
authors = models.ManyToManyField(Author)
|
||||||
|
|
||||||
|
With these models, a call to ``form_for_model(Author)`` would return a ``Form``
|
||||||
|
class equivalent to this::
|
||||||
|
|
||||||
|
class AuthorForm(forms.Form):
|
||||||
|
name = forms.CharField(max_length=100)
|
||||||
|
title = forms.CharField(max_length=3,
|
||||||
|
widget=forms.Select(choices=TITLE_CHOICES))
|
||||||
|
birth_date = forms.DateField(required=False)
|
||||||
|
|
||||||
|
A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to
|
||||||
|
this::
|
||||||
|
|
||||||
|
class BookForm(forms.Form):
|
||||||
|
name = forms.CharField(max_length=100)
|
||||||
|
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
|
||||||
|
|
||||||
|
The ``save()`` method
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Every form produced by ``form_for_model()`` also has a ``save()`` method. This
|
||||||
|
method creates and saves a database object from the data bound to the form. For
|
||||||
|
example::
|
||||||
|
|
||||||
|
# Create a form instance from POST data.
|
||||||
|
>>> f = ArticleForm(request.POST)
|
||||||
|
|
||||||
|
# Save a new Article object from the form's data.
|
||||||
|
>>> new_article = f.save()
|
||||||
|
|
||||||
|
Note that ``save()`` will raise a ``ValueError`` if the data in the form
|
||||||
|
doesn't validate -- i.e., ``if form.errors``.
|
||||||
|
|
||||||
|
Using an alternate base class
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If you want to add custom methods to the form generated by
|
||||||
|
``form_for_model()``, write a class that extends ``django.newforms.BaseForm``
|
||||||
|
and contains your custom methods. Then, use the ``form`` argument to
|
||||||
|
``form_for_model()`` to tell it to use your custom form as its base class.
|
||||||
|
For example::
|
||||||
|
|
||||||
|
# Create the new base class.
|
||||||
|
>>> class MyBase(BaseForm):
|
||||||
|
... def my_method(self):
|
||||||
|
... # Do whatever the method does
|
||||||
|
|
||||||
|
# Create the form class with a different base class.
|
||||||
|
>>> ArticleForm = form_for_model(Article, form=MyBase)
|
||||||
|
|
||||||
|
# Instantiate the form.
|
||||||
|
>>> f = ArticleForm()
|
||||||
|
|
||||||
|
# Use the base class method.
|
||||||
|
>>> f.my_method()
|
||||||
|
|
||||||
|
Using a subset of fields on the form
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
In some cases, you may not want all the model fields to appear on the generated
|
||||||
|
form. There are two ways of telling ``form_for_model()`` to use only a subset
|
||||||
|
of the model fields:
|
||||||
|
|
||||||
|
1. Set ``editable=False`` on the model field. As a result, *any* form
|
||||||
|
created from the model via ``form_for_model()`` will not include that
|
||||||
|
field.
|
||||||
|
|
||||||
|
2. Use the ``fields`` argument to ``form_for_model()``. This argument, if
|
||||||
|
given, should be a list of field names to include in the form.
|
||||||
|
|
||||||
|
For example, if you want a form for the ``Author`` model (defined above)
|
||||||
|
that includes only the ``name`` and ``title`` fields, you would specify
|
||||||
|
``fields`` like this::
|
||||||
|
|
||||||
|
PartialArticleForm = form_for_model(Author, fields=('name', 'title'))
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If you specify ``fields`` when creating a form with ``form_for_model()``,
|
||||||
|
make sure that the fields that are *not* specified can provide default
|
||||||
|
values, or are allowed to have a value of ``None``. If a field isn't
|
||||||
|
specified on a form, the object created from the form can't provide
|
||||||
|
a value for that attribute, which will prevent the new instance from
|
||||||
|
being saved.
|
||||||
|
|
||||||
|
Overriding the default field types
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The default field types, as described in the "Field types" table above, are
|
||||||
|
sensible defaults; if you have a ``DateField`` in your model, chances are you'd
|
||||||
|
want that to be represented as a ``DateField`` in your form. But
|
||||||
|
``form_for_model()`` gives you the flexibility of changing the form field type
|
||||||
|
for a given model field. You do this by specifying a **formfield callback**.
|
||||||
|
|
||||||
|
A formfield callback is a function that, when provided with a model field,
|
||||||
|
returns a form field instance. When constructing a form, ``form_for_model()``
|
||||||
|
asks the formfield callback to provide form field types.
|
||||||
|
|
||||||
|
By default, ``form_for_model()`` calls the ``formfield()`` method on the model
|
||||||
|
field::
|
||||||
|
|
||||||
|
def default_callback(field, **kwargs):
|
||||||
|
return field.formfield(**kwargs)
|
||||||
|
|
||||||
|
The ``kwargs`` are any keyword arguments that might be passed to the form
|
||||||
|
field, such as ``required=True`` or ``label='Foo'``.
|
||||||
|
|
||||||
|
For example, if you wanted to use ``MyDateFormField`` for any ``DateField``
|
||||||
|
field on the model, you could define the callback::
|
||||||
|
|
||||||
|
>>> def my_callback(field, **kwargs):
|
||||||
|
... if isinstance(field, models.DateField):
|
||||||
|
... return MyDateFormField(**kwargs)
|
||||||
|
... else:
|
||||||
|
... return field.formfield(**kwargs)
|
||||||
|
|
||||||
|
>>> ArticleForm = form_for_model(formfield_callback=my_callback)
|
||||||
|
|
||||||
|
Note that your callback needs to handle *all* possible model field types, not
|
||||||
|
just the ones that you want to behave differently to the default. That's why
|
||||||
|
this example has an ``else`` clause that implements the default behavior.
|
||||||
|
|
||||||
|
Finding the model associated with a form
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The model class that was used to construct the form is available
|
||||||
|
using the ``_model`` property of the generated form::
|
||||||
|
|
||||||
|
>>> ArticleForm = form_for_model(Article)
|
||||||
|
>>> ArticleForm._model
|
||||||
|
<class 'myapp.models.Article'>
|
||||||
|
|
||||||
|
``form_for_instance()``
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
``form_for_instance()`` is like ``form_for_model()``, but it takes a model
|
||||||
|
instance instead of a model class::
|
||||||
|
|
||||||
|
# Create an Author.
|
||||||
|
>>> a = Author(name='Joe Smith', title='MR', birth_date=None)
|
||||||
|
>>> a.save()
|
||||||
|
|
||||||
|
# Create a form for this particular Author.
|
||||||
|
>>> AuthorForm = form_for_instance(a)
|
||||||
|
|
||||||
|
# Instantiate the form.
|
||||||
|
>>> f = AuthorForm()
|
||||||
|
|
||||||
|
When a form created by ``form_for_instance()`` is created, the initial
|
||||||
|
data values for the form fields are drawn from the instance. However,
|
||||||
|
this data is not bound to the form. You will need to bind data to the
|
||||||
|
form before the form can be saved.
|
||||||
|
|
||||||
|
When you call ``save()`` on a form created by ``form_for_instance()``,
|
||||||
|
the database instance will be updated. As in ``form_for_model()``, ``save()``
|
||||||
|
will raise ``ValueError`` if the data doesn't validate.
|
||||||
|
|
||||||
|
``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
|
||||||
|
arguments that behave the same way as they do for ``form_for_model()``.
|
||||||
|
|
||||||
|
When should you use ``form_for_model()`` and ``form_for_instance()``?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be
|
||||||
|
shortcuts for the common case. If you want to create a form whose fields map to
|
||||||
|
more than one model, or a form that contains fields that *aren't* on a model,
|
||||||
|
you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way
|
||||||
|
isn't that difficult, after all.
|
||||||
|
|
||||||
More coming soon
|
More coming soon
|
||||||
================
|
================
|
||||||
|
|
||||||
@ -880,6 +1182,3 @@ what's possible.
|
|||||||
|
|
||||||
If you're really itching to learn and use this library, please be patient.
|
If you're really itching to learn and use this library, please be patient.
|
||||||
We're working hard on finishing both the code and documentation.
|
We're working hard on finishing both the code and documentation.
|
||||||
|
|
||||||
Widgets
|
|
||||||
=======
|
|
||||||
|
@ -717,7 +717,7 @@ object::
|
|||||||
# split_contents() knows not to split quoted strings.
|
# split_contents() knows not to split quoted strings.
|
||||||
tag_name, format_string = token.split_contents()
|
tag_name, format_string = token.split_contents()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents[0]
|
raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
|
||||||
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
||||||
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
||||||
return CurrentTimeNode(format_string[1:-1])
|
return CurrentTimeNode(format_string[1:-1])
|
||||||
@ -846,7 +846,7 @@ Now your tag should begin to look like this::
|
|||||||
# split_contents() knows not to split quoted strings.
|
# split_contents() knows not to split quoted strings.
|
||||||
tag_name, date_to_be_formatted, format_string = token.split_contents()
|
tag_name, date_to_be_formatted, format_string = token.split_contents()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents[0]
|
raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
|
||||||
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
||||||
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
||||||
return FormatTimeNode(date_to_be_formatted, format_string[1:-1])
|
return FormatTimeNode(date_to_be_formatted, format_string[1:-1])
|
||||||
@ -1080,7 +1080,7 @@ class, like so::
|
|||||||
# Splitting by None == splitting by spaces.
|
# Splitting by None == splitting by spaces.
|
||||||
tag_name, arg = token.contents.split(None, 1)
|
tag_name, arg = token.contents.split(None, 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents[0]
|
raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
|
||||||
m = re.search(r'(.*?) as (\w+)', arg)
|
m = re.search(r'(.*?) as (\w+)', arg)
|
||||||
if not m:
|
if not m:
|
||||||
raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
|
raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
|
||||||
|
@ -177,7 +177,7 @@ tools that can be used to establish tests and test conditions.
|
|||||||
|
|
||||||
* `Test Client`_
|
* `Test Client`_
|
||||||
* `TestCase`_
|
* `TestCase`_
|
||||||
* `Email services`_
|
* `E-mail services`_
|
||||||
|
|
||||||
Test Client
|
Test Client
|
||||||
-----------
|
-----------
|
||||||
@ -459,9 +459,9 @@ Emptying the test outbox
|
|||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
|
||||||
At the start of each test case, in addition to installing fixtures,
|
At the start of each test case, in addition to installing fixtures,
|
||||||
Django clears the contents of the test email outbox.
|
Django clears the contents of the test e-mail outbox.
|
||||||
|
|
||||||
For more detail on email services during tests, see `Email services`_.
|
For more detail on e-mail services during tests, see `E-mail services`_.
|
||||||
|
|
||||||
Assertions
|
Assertions
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
@ -502,16 +502,17 @@ that can be useful in testing the behavior of web sites.
|
|||||||
Assert that the template with the given name was used in rendering the
|
Assert that the template with the given name was used in rendering the
|
||||||
response.
|
response.
|
||||||
|
|
||||||
Email services
|
E-mail services
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
|
||||||
If your view makes use of the `Django email services`_, you don't really
|
If your view makes use of the `Django e-mail services`_, you don't really
|
||||||
want email to be sent every time you run a test using that view.
|
want e-mail to be sent every time you run a test using that view.
|
||||||
|
|
||||||
When the Django test framework is initialized, it transparently replaces the
|
When the Django test framework is initialized, it transparently replaces the
|
||||||
normal `SMTPConnection`_ class with a dummy implementation that redirects all
|
normal `SMTPConnection`_ class with a dummy implementation that redirects all
|
||||||
email to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``,
|
e-mail to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``,
|
||||||
is a simple list of all `EmailMessage`_ instances that have been sent.
|
is a simple list of all `EmailMessage`_ instances that have been sent.
|
||||||
For example, during test conditions, it would be possible to run the following
|
For example, during test conditions, it would be possible to run the following
|
||||||
code::
|
code::
|
||||||
@ -541,7 +542,7 @@ to mail.outbox::
|
|||||||
# Empty the test outbox
|
# Empty the test outbox
|
||||||
mail.outbox = []
|
mail.outbox = []
|
||||||
|
|
||||||
.. _`Django email services`: ../email/
|
.. _`Django e-mail services`: ../email/
|
||||||
.. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes
|
.. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes
|
||||||
.. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes
|
.. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes
|
||||||
.. _`previously`: #emptying-the-test-outbox
|
.. _`previously`: #emptying-the-test-outbox
|
||||||
@ -669,7 +670,7 @@ a number of utility methods in the ``django.test.utils`` module.
|
|||||||
|
|
||||||
``teardown_test_environment()``
|
``teardown_test_environment()``
|
||||||
Performs any global post-test teardown, such as removing the instrumentation
|
Performs any global post-test teardown, such as removing the instrumentation
|
||||||
of the template rendering system and restoring normal email services.
|
of the template rendering system and restoring normal e-mail services.
|
||||||
|
|
||||||
``create_test_db(verbosity=1, autoclobber=False)``
|
``create_test_db(verbosity=1, autoclobber=False)``
|
||||||
Creates a new test database, and run ``syncdb`` against it.
|
Creates a new test database, and run ``syncdb`` against it.
|
||||||
|
@ -179,6 +179,18 @@ fields with the 'choices' attribute are represented by a ChoiceField.
|
|||||||
<option value="3">Third test</option>
|
<option value="3">Third test</option>
|
||||||
</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>
|
</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>
|
||||||
|
|
||||||
|
You can restrict a form to a subset of the complete list of fields
|
||||||
|
by providing a 'fields' argument. If you try to save a
|
||||||
|
model created with such a form, you need to ensure that the fields
|
||||||
|
that are _not_ on the form have default values, or are allowed to have
|
||||||
|
a value of None. If a field isn't specified on a form, the object created
|
||||||
|
from the form can't provide a value for that field!
|
||||||
|
>>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date'))
|
||||||
|
>>> f = PartialArticleForm(auto_id=False)
|
||||||
|
>>> print f
|
||||||
|
<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
|
||||||
|
<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
|
||||||
|
|
||||||
You can pass a custom Form class to form_for_model. Make sure it's a
|
You can pass a custom Form class to form_for_model. Make sure it's a
|
||||||
subclass of BaseForm, not Form.
|
subclass of BaseForm, not Form.
|
||||||
>>> class CustomForm(BaseForm):
|
>>> class CustomForm(BaseForm):
|
||||||
@ -224,7 +236,23 @@ current values are inserted as 'initial' data in each Field.
|
|||||||
<option value="2">It's a test</option>
|
<option value="2">It's a test</option>
|
||||||
<option value="3">Third test</option>
|
<option value="3">Third test</option>
|
||||||
</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
|
</select> Hold down "Control", or "Command" on a Mac, to select more than one.</li>
|
||||||
>>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 'writer': u'1', 'article': 'Hello.'})
|
>>> f = TestArticleForm({'headline': u'Test headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'})
|
||||||
|
>>> f.is_valid()
|
||||||
|
True
|
||||||
|
>>> test_art = f.save()
|
||||||
|
>>> test_art.id
|
||||||
|
1
|
||||||
|
>>> test_art = Article.objects.get(id=1)
|
||||||
|
>>> test_art.headline
|
||||||
|
u'Test headline'
|
||||||
|
|
||||||
|
You can create a form over a subset of the available fields
|
||||||
|
by specifying a 'fields' argument to form_for_instance.
|
||||||
|
>>> PartialArticleForm = form_for_instance(art, fields=('headline','pub_date'))
|
||||||
|
>>> f = PartialArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04'}, auto_id=False)
|
||||||
|
>>> print f.as_ul()
|
||||||
|
<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
|
||||||
|
<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
|
||||||
>>> f.is_valid()
|
>>> f.is_valid()
|
||||||
True
|
True
|
||||||
>>> new_art = f.save()
|
>>> new_art = f.save()
|
||||||
|
@ -2752,6 +2752,64 @@ then the latter will get precedence.
|
|||||||
<li>Username: <input type="text" name="username" value="babik" maxlength="10" /></li>
|
<li>Username: <input type="text" name="username" value="babik" maxlength="10" /></li>
|
||||||
<li>Password: <input type="password" name="password" /></li>
|
<li>Password: <input type="password" name="password" /></li>
|
||||||
|
|
||||||
|
# Callable initial data ########################################################
|
||||||
|
|
||||||
|
The previous technique dealt with raw values as initial data, but it's also
|
||||||
|
possible to specify callable data.
|
||||||
|
|
||||||
|
>>> class UserRegistration(Form):
|
||||||
|
... username = CharField(max_length=10)
|
||||||
|
... password = CharField(widget=PasswordInput)
|
||||||
|
|
||||||
|
We need to define functions that get called later.
|
||||||
|
>>> def initial_django():
|
||||||
|
... return 'django'
|
||||||
|
>>> def initial_stephane():
|
||||||
|
... return 'stephane'
|
||||||
|
|
||||||
|
Here, we're not submitting any data, so the initial value will be displayed.
|
||||||
|
>>> p = UserRegistration(initial={'username': initial_django}, auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
|
||||||
|
<li>Password: <input type="password" name="password" /></li>
|
||||||
|
|
||||||
|
The 'initial' parameter is meaningless if you pass data.
|
||||||
|
>>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
|
||||||
|
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
|
||||||
|
>>> p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
|
||||||
|
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
|
||||||
|
>>> p = UserRegistration({'username': u'foo'}, initial={'username': initial_django}, auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li>
|
||||||
|
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
|
||||||
|
|
||||||
|
A callable 'initial' value is *not* used as a fallback if data is not provided.
|
||||||
|
In this example, we don't provide a value for 'username', and the form raises a
|
||||||
|
validation error rather than using the initial value for 'username'.
|
||||||
|
>>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django})
|
||||||
|
>>> p.errors
|
||||||
|
{'username': [u'This field is required.']}
|
||||||
|
>>> p.is_valid()
|
||||||
|
False
|
||||||
|
|
||||||
|
If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
|
||||||
|
then the latter will get precedence.
|
||||||
|
>>> class UserRegistration(Form):
|
||||||
|
... username = CharField(max_length=10, initial=initial_django)
|
||||||
|
... password = CharField(widget=PasswordInput)
|
||||||
|
>>> p = UserRegistration(auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
|
||||||
|
<li>Password: <input type="password" name="password" /></li>
|
||||||
|
>>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False)
|
||||||
|
>>> print p.as_ul()
|
||||||
|
<li>Username: <input type="text" name="username" value="stephane" maxlength="10" /></li>
|
||||||
|
<li>Password: <input type="password" name="password" /></li>
|
||||||
|
|
||||||
# Help text ###################################################################
|
# Help text ###################################################################
|
||||||
|
|
||||||
You can specify descriptive text for a field by using the 'help_text' argument
|
You can specify descriptive text for a field by using the 'help_text' argument
|
||||||
|
@ -96,6 +96,12 @@ MultiValueDictKeyError: "Key 'foo' not found in <MultiValueDict: {}>"
|
|||||||
>>> q['name']
|
>>> q['name']
|
||||||
u'john'
|
u'john'
|
||||||
|
|
||||||
|
>>> del q['name']
|
||||||
|
>>> 'name' in q
|
||||||
|
False
|
||||||
|
|
||||||
|
>>> q['name'] = 'john'
|
||||||
|
|
||||||
>>> q.get('foo', 'default')
|
>>> q.get('foo', 'default')
|
||||||
u'default'
|
u'default'
|
||||||
|
|
||||||
@ -367,6 +373,11 @@ AttributeError: This QueryDict instance is immutable
|
|||||||
>>> q.urlencode()
|
>>> q.urlencode()
|
||||||
'vote=yes&vote=no'
|
'vote=yes&vote=no'
|
||||||
|
|
||||||
|
>>> del q['vote']
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
AttributeError: This QueryDict instance is immutable
|
||||||
|
|
||||||
# QueryDicts must be able to handle invalid input encoding (in this case, bad
|
# QueryDicts must be able to handle invalid input encoding (in this case, bad
|
||||||
# UTF-8 encoding).
|
# UTF-8 encoding).
|
||||||
>>> q = QueryDict('foo=bar&foo=\xff')
|
>>> q = QueryDict('foo=bar&foo=\xff')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user