mirror of
https://github.com/django/django.git
synced 2025-07-04 01:39:20 +00:00
unicode: Merged from trunk up to [5443].
git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5444 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8d30cdc267
commit
b792044d34
@ -6,6 +6,7 @@ from django.template import get_library, Library, InvalidTemplateLibrary
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import smart_str
|
||||
import sys
|
||||
import re
|
||||
|
||||
register = Library()
|
||||
|
||||
@ -62,8 +63,8 @@ class FirstOfNode(Node):
|
||||
return ''
|
||||
|
||||
class ForNode(Node):
|
||||
def __init__(self, loopvar, sequence, reversed, nodelist_loop):
|
||||
self.loopvar, self.sequence = loopvar, sequence
|
||||
def __init__(self, loopvars, sequence, reversed, nodelist_loop):
|
||||
self.loopvars, self.sequence = loopvars, sequence
|
||||
self.reversed = reversed
|
||||
self.nodelist_loop = nodelist_loop
|
||||
|
||||
@ -73,7 +74,7 @@ class ForNode(Node):
|
||||
else:
|
||||
reversed = ''
|
||||
return "<For Node: for %s in %s, tail_len: %d%s>" % \
|
||||
(self.loopvar, self.sequence, len(self.nodelist_loop), reversed)
|
||||
(', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed)
|
||||
|
||||
def __iter__(self):
|
||||
for node in self.nodelist_loop:
|
||||
@ -108,6 +109,7 @@ class ForNode(Node):
|
||||
for index in range(len(data)-1, -1, -1):
|
||||
yield data[index]
|
||||
values = reverse(values)
|
||||
unpack = len(self.loopvars) > 1
|
||||
for i, item in enumerate(values):
|
||||
context['forloop'] = {
|
||||
# shortcuts for current loop iteration number
|
||||
@ -121,9 +123,20 @@ class ForNode(Node):
|
||||
'last': (i == len_values - 1),
|
||||
'parentloop': parentloop,
|
||||
}
|
||||
context[self.loopvar] = item
|
||||
if unpack:
|
||||
# If there are multiple loop variables, unpack the item into them.
|
||||
context.update(dict(zip(self.loopvars, item)))
|
||||
else:
|
||||
context[self.loopvars[0]] = item
|
||||
for node in self.nodelist_loop:
|
||||
nodelist.append(node.render(context))
|
||||
if unpack:
|
||||
# The loop variables were pushed on to the context so pop them
|
||||
# off again. This is necessary because the tag lets the length
|
||||
# of loopvars differ to the length of each set of items and we
|
||||
# don't want to leave any vars from the previous loop on the
|
||||
# context.
|
||||
context.pop()
|
||||
context.pop()
|
||||
return nodelist.render(context)
|
||||
|
||||
@ -487,7 +500,7 @@ def do_filter(parser, token):
|
||||
nodelist = parser.parse(('endfilter',))
|
||||
parser.delete_first_token()
|
||||
return FilterNode(filter_expr, nodelist)
|
||||
filter = register.tag("filter", do_filter)
|
||||
do_filter = register.tag("filter", do_filter)
|
||||
|
||||
#@register.tag
|
||||
def firstof(parser, token):
|
||||
@ -531,8 +544,14 @@ def do_for(parser, token):
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
You can also loop over a list in reverse by using
|
||||
You can loop over a list in reverse by using
|
||||
``{% for obj in list reversed %}``.
|
||||
|
||||
You can also unpack multiple values from a two-dimensional array::
|
||||
|
||||
{% for key,value in dict.items %}
|
||||
{{ key }}: {{ value }}
|
||||
{% endfor %}
|
||||
|
||||
The for loop sets a number of variables available within the loop:
|
||||
|
||||
@ -553,18 +572,23 @@ def do_for(parser, token):
|
||||
|
||||
"""
|
||||
bits = token.contents.split()
|
||||
if len(bits) == 5 and bits[4] != 'reversed':
|
||||
raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
|
||||
if len(bits) not in (4, 5):
|
||||
raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
|
||||
if bits[2] != 'in':
|
||||
raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
|
||||
loopvar = bits[1]
|
||||
sequence = parser.compile_filter(bits[3])
|
||||
reversed = (len(bits) == 5)
|
||||
if len(bits) < 4:
|
||||
raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents
|
||||
|
||||
reversed = bits[-1] == 'reversed'
|
||||
in_index = reversed and -3 or -2
|
||||
if bits[in_index] != 'in':
|
||||
raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents
|
||||
|
||||
loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',')
|
||||
for var in loopvars:
|
||||
if not var or ' ' in var:
|
||||
raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents
|
||||
|
||||
sequence = parser.compile_filter(bits[in_index+1])
|
||||
nodelist_loop = parser.parse(('endfor',))
|
||||
parser.delete_first_token()
|
||||
return ForNode(loopvar, sequence, reversed, nodelist_loop)
|
||||
return ForNode(loopvars, sequence, reversed, nodelist_loop)
|
||||
do_for = register.tag("for", do_for)
|
||||
|
||||
def do_ifequal(parser, token, negate):
|
||||
|
@ -6,8 +6,9 @@ Django aims to follow Python's `"batteries included" philosophy`_. It ships
|
||||
with a variety of extra, optional tools that solve common Web-development
|
||||
problems.
|
||||
|
||||
This code lives in ``django/contrib`` in the Django distribution. Here's a
|
||||
rundown of the packages in ``contrib``:
|
||||
This code lives in ``django/contrib`` in the Django distribution. This document
|
||||
gives a rundown of the packages in ``contrib``, along with any dependencies
|
||||
those packages have.
|
||||
|
||||
.. admonition:: Note
|
||||
|
||||
@ -26,6 +27,8 @@ The automatic Django administrative interface. For more information, see
|
||||
|
||||
.. _Tutorial 2: ../tutorial02/
|
||||
|
||||
Requires the auth_ and contenttypes_ contrib packages to be installed.
|
||||
|
||||
auth
|
||||
====
|
||||
|
||||
@ -144,6 +147,8 @@ See the `flatpages documentation`_.
|
||||
|
||||
.. _flatpages documentation: ../flatpages/
|
||||
|
||||
Requires the sites_ contrib package to be installed as well.
|
||||
|
||||
localflavor
|
||||
===========
|
||||
|
||||
|
@ -134,6 +134,15 @@ the database until you explicitly call ``save()``.
|
||||
|
||||
The ``save()`` method has no return value.
|
||||
|
||||
Updating ``ForeignKey`` fields works exactly the same way; simply assign an
|
||||
object of the right type to the field in question::
|
||||
|
||||
joe = Author.objects.create(name="Joe")
|
||||
entry.author = joe
|
||||
entry.save()
|
||||
|
||||
Django will complain if you try to assign an object of the wrong type.
|
||||
|
||||
How Django knows to UPDATE vs. INSERT
|
||||
-------------------------------------
|
||||
|
||||
@ -1229,8 +1238,8 @@ whose ``headline`` contains ``'Lennon'``::
|
||||
|
||||
Blog.objects.filter(entry__headline__contains='Lennon')
|
||||
|
||||
Escaping parenthesis and underscores in LIKE statements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Escaping percent signs and underscores in LIKE statements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The field lookups that equate to ``LIKE`` SQL statements (``iexact``,
|
||||
``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith``
|
||||
|
@ -203,7 +203,7 @@ This is probably the most common case, if you're using Django's admin site::
|
||||
DocumentRoot /home/user/public_html
|
||||
Alias /media /home/user/python/django/contrib/admin/media
|
||||
RewriteEngine On
|
||||
RewriteRule ^/(media.*)$ /$1 [QSA,L]
|
||||
RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
|
||||
</VirtualHost>
|
||||
|
@ -1890,14 +1890,15 @@ rows. Example::
|
||||
row = cursor.fetchone()
|
||||
return row
|
||||
|
||||
``connection`` and ``cursor`` simply use the standard `Python DB-API`_. If
|
||||
you're not familiar with the Python DB-API, note that the SQL statement in
|
||||
``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters
|
||||
directly within the SQL. If you use this technique, the underlying database
|
||||
library will automatically add quotes and escaping to your parameter(s) as
|
||||
necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the
|
||||
``"?"`` placeholder, which is used by the SQLite Python bindings. This is for
|
||||
the sake of consistency and sanity.)
|
||||
``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_
|
||||
(except when it comes to `transaction handling`_). If you're not familiar with
|
||||
the Python DB-API, note that the SQL statement in ``cursor.execute()`` uses
|
||||
placeholders, ``"%s"``, rather than adding parameters directly within the SQL.
|
||||
If you use this technique, the underlying database library will automatically
|
||||
add quotes and escaping to your parameter(s) as necessary. (Also note that
|
||||
Django expects the ``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is
|
||||
used by the SQLite Python bindings. This is for the sake of consistency and
|
||||
sanity.)
|
||||
|
||||
A final note: If all you want to do is a custom ``WHERE`` clause, you can just
|
||||
just the ``where``, ``tables`` and ``params`` arguments to the standard lookup
|
||||
@ -1905,6 +1906,7 @@ API. See `Other lookup options`_.
|
||||
|
||||
.. _Python DB-API: http://www.python.org/peps/pep-0249.html
|
||||
.. _Other lookup options: ../db-api/#extra-params-select-where-tables
|
||||
.. _transaction handling: ../transactions/
|
||||
|
||||
Overriding default model methods
|
||||
--------------------------------
|
||||
|
@ -51,9 +51,17 @@ whereas ``<Location>`` points at places in the URL structure of a Web site.
|
||||
``<Directory>`` would be meaningless here.
|
||||
|
||||
Also, if you've manually altered your ``PYTHONPATH`` to put your Django project
|
||||
on it, you'll need to tell mod_python::
|
||||
on it, you'll need to tell mod_python:
|
||||
|
||||
PythonPath "['/path/to/project'] + sys.path"
|
||||
.. parsed-literal::
|
||||
|
||||
<Location "/mysite/">
|
||||
SetHandler python-program
|
||||
PythonHandler django.core.handlers.modpython
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonDebug On
|
||||
**PythonPath "['/path/to/project'] + sys.path"**
|
||||
</Location>
|
||||
|
||||
.. caution::
|
||||
|
||||
|
@ -299,12 +299,14 @@ required. In this example, the data dictionary doesn't include a value for the
|
||||
In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an
|
||||
empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat
|
||||
empty values as an empty string. Each field type knows what its "blank" value
|
||||
is -- e.g., for ``DateField``, it's ``None`` instead of the empty string.
|
||||
is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. For
|
||||
full details on each field's behavior in this case, see the "Empty value" note
|
||||
for each field in the "Built-in ``Field`` classes" section below.
|
||||
|
||||
Behavior of unbound forms
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's meaningless to request "clean" data in a form with no data, but, for the
|
||||
It's meaningless to request "cleaned" data in a form with no data, but, for the
|
||||
record, here's what happens with unbound forms::
|
||||
|
||||
>>> f = ContactForm()
|
||||
@ -606,8 +608,13 @@ Using forms in views and templates
|
||||
----------------------------------
|
||||
|
||||
Let's put this all together and use the ``ContactForm`` example in a Django
|
||||
view and template. This example view displays the contact form by default and
|
||||
validates/processes it if accessed via a POST request::
|
||||
view and template.
|
||||
|
||||
Simple view example
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This example view displays the contact form by default and validates/processes
|
||||
it if accessed via a POST request::
|
||||
|
||||
def contact(request):
|
||||
if request.method == 'POST':
|
||||
@ -619,12 +626,12 @@ validates/processes it if accessed via a POST request::
|
||||
form = ContactForm()
|
||||
return render_to_response('contact.html', {'form': form})
|
||||
|
||||
Simple template output
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Simple template example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The template, ``contact.html``, is responsible for displaying the form as HTML.
|
||||
To do this, we can use the techniques outlined in the "Outputting forms as HTML"
|
||||
section above.
|
||||
The template in the above view example, ``contact.html``, is responsible for
|
||||
displaying the form as HTML. To do this, we can use the techniques outlined in
|
||||
the "Outputting forms as HTML" section above.
|
||||
|
||||
The simplest way to display a form's HTML is to use the variable on its own,
|
||||
like this::
|
||||
@ -677,7 +684,7 @@ The easiest way is to iterate over the form's fields, with
|
||||
|
||||
This iteration technique is useful if you want to apply the same HTML
|
||||
formatting to each field, or if you don't know the names of the form fields
|
||||
ahead of time. Note that the fields will be listed in the order in which
|
||||
ahead of time. Note that the fields will be iterated over in the order in which
|
||||
they're defined in the ``Form`` class.
|
||||
|
||||
Alternatively, you can arrange the form's fields explicitly, by name. Do that
|
||||
@ -701,7 +708,10 @@ For example::
|
||||
Subclassing forms
|
||||
-----------------
|
||||
|
||||
If you subclass a custom ``Form`` class, the resulting ``Form`` class will
|
||||
If you have multiple ``Form`` classes that share fields, you can use
|
||||
subclassing to remove redundancy.
|
||||
|
||||
When you subclass a custom ``Form`` class, the resulting subclass will
|
||||
include all fields of the parent class(es), followed by the fields you define
|
||||
in the subclass.
|
||||
|
||||
@ -1202,6 +1212,36 @@ custom ``Field`` classes. To do this, just create a subclass of
|
||||
mentioned above (``required``, ``label``, ``initial``, ``widget``,
|
||||
``help_text``).
|
||||
|
||||
A simple example
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Here's a simple example of a custom field that validates its input is a string
|
||||
containing comma-separated e-mail addresses, with at least one address. We'll
|
||||
keep it simple and assume e-mail validation is contained in a function called
|
||||
``is_valid_email()``. The full class::
|
||||
|
||||
from django import newforms as forms
|
||||
|
||||
class MultiEmailField(forms.Field):
|
||||
def clean(self, value):
|
||||
emails = value.split(',')
|
||||
for email in emails:
|
||||
if not is_valid_email(email):
|
||||
raise forms.ValidationError('%s is not a valid e-mail address.' % email)
|
||||
if not emails:
|
||||
raise forms.ValidationError('Enter at least one e-mail address.')
|
||||
return emails
|
||||
|
||||
Let's alter the ongoing ``ContactForm`` example to demonstrate how you'd use
|
||||
this in a form. Simply use ``MultiEmailField`` instead of ``forms.EmailField``,
|
||||
like so::
|
||||
|
||||
class ContactForm(forms.Form):
|
||||
subject = forms.CharField(max_length=100)
|
||||
message = forms.CharField()
|
||||
senders = MultiEmailField()
|
||||
cc_myself = forms.BooleanField()
|
||||
|
||||
Generating forms for models
|
||||
===========================
|
||||
|
||||
|
@ -91,9 +91,12 @@ Filters can be "chained." The output of one filter is applied to the next.
|
||||
``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents,
|
||||
then converting line breaks to ``<p>`` tags.
|
||||
|
||||
Some filters take arguments. A filter argument looks like this:
|
||||
``{{ bio|truncatewords:"30" }}``. This will display the first 30 words of the
|
||||
``bio`` variable. Filter arguments always are in double quotes.
|
||||
Some filters take arguments. A filter argument looks like this: ``{{
|
||||
bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio``
|
||||
variable.
|
||||
|
||||
Filter arguments that contain spaces must be quoted; for example, to join a list
|
||||
with commas and spaced you'd use ``{{ list|join:", " }}``.
|
||||
|
||||
The `Built-in filter reference`_ below describes all the built-in filters.
|
||||
|
||||
@ -444,7 +447,7 @@ for
|
||||
~~~
|
||||
|
||||
Loop over each item in an array. For example, to display a list of athletes
|
||||
given ``athlete_list``::
|
||||
provided in ``athlete_list``::
|
||||
|
||||
<ul>
|
||||
{% for athlete in athlete_list %}
|
||||
@ -452,7 +455,25 @@ given ``athlete_list``::
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
You can also loop over a list in reverse by using ``{% for obj in list reversed %}``.
|
||||
You can loop over a list in reverse by using ``{% for obj in list reversed %}``.
|
||||
|
||||
**New in Django development version**
|
||||
If you need to loop over a list of lists, you can unpack the values
|
||||
in eachs sub-list into a set of known names. For example, if your context contains
|
||||
a list of (x,y) coordinates called ``points``, you could use the following
|
||||
to output the list of points::
|
||||
|
||||
{% for x, y in points %}
|
||||
There is a point at {{ x }},{{ y }}
|
||||
{% endfor %}
|
||||
|
||||
This can also be useful if you need to access the items in a dictionary.
|
||||
For example, if your context contained a dictionary ``data``, the following
|
||||
would display the keys and values of the dictionary::
|
||||
|
||||
{% for key, value in data.items %}
|
||||
{{ key }}: {{ value }}
|
||||
{% endfor %}
|
||||
|
||||
The for loop sets a number of variables available within the loop:
|
||||
|
||||
|
@ -295,6 +295,20 @@ class Templates(unittest.TestCase):
|
||||
'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
|
||||
'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
|
||||
'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),
|
||||
'for-tag-unpack01': ("{% for key,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||
'for-tag-unpack03': ("{% for key, value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||
'for-tag-unpack04': ("{% for key , value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||
'for-tag-unpack05': ("{% for key ,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||
'for-tag-unpack06': ("{% for key value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
|
||||
'for-tag-unpack07': ("{% for key,,value in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
|
||||
'for-tag-unpack08': ("{% for key,value, in items %}{{ key }}:{{ value }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, template.TemplateSyntaxError),
|
||||
# Ensure that a single loopvar doesn't truncate the list in val.
|
||||
'for-tag-unpack09': ("{% for val in items %}{{ val.0 }}:{{ val.1 }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, "one:1/two:2/"),
|
||||
# Otherwise, silently truncate if the length of loopvars differs to the length of each set of items.
|
||||
'for-tag-unpack10': ("{% for x,y in items %}{{ x }}:{{ y }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'orange'))}, "one:1/two:2/"),
|
||||
'for-tag-unpack11': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1), ('two', 2))}, ("one:1,/two:2,/", "one:1,INVALID/two:2,INVALID/")),
|
||||
'for-tag-unpack12': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")),
|
||||
'for-tag-unpack13': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'cheese'))}, ("one:1,carrot/two:2,cheese/", "one:1,carrot/two:2,cheese/")),
|
||||
|
||||
### IF TAG ################################################################
|
||||
'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user