mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Merged to [6155]
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6332 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
c8f6e485b8
commit
fb6a0c8ffa
2
AUTHORS
2
AUTHORS
@ -127,6 +127,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Dimitris Glezos <dimitris@glezos.com>
|
Dimitris Glezos <dimitris@glezos.com>
|
||||||
glin@seznam.cz
|
glin@seznam.cz
|
||||||
martin.glueck@gmail.com
|
martin.glueck@gmail.com
|
||||||
|
Artyom Gnilov <boobsd@gmail.com>
|
||||||
GomoX <gomo@datafull.com>
|
GomoX <gomo@datafull.com>
|
||||||
Mario Gonzalez <gonzalemario@gmail.com>
|
Mario Gonzalez <gonzalemario@gmail.com>
|
||||||
pradeep.gowda@gmail.com
|
pradeep.gowda@gmail.com
|
||||||
@ -240,6 +241,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Jan Rademaker
|
Jan Rademaker
|
||||||
Michael Radziej <mir@noris.de>
|
Michael Radziej <mir@noris.de>
|
||||||
Amit Ramon <amit.ramon@gmail.com>
|
Amit Ramon <amit.ramon@gmail.com>
|
||||||
|
Philippe Raoult <philippe.raoult@n2nsoft.com>
|
||||||
Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
|
Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
|
||||||
Brian Ray <http://brianray.chipy.org/>
|
Brian Ray <http://brianray.chipy.org/>
|
||||||
remco@diji.biz
|
remco@diji.biz
|
||||||
|
@ -40,6 +40,9 @@ var RUSSIAN_MAP = {
|
|||||||
'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu',
|
'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu',
|
||||||
'Я':'Ya'
|
'Я':'Ya'
|
||||||
}
|
}
|
||||||
|
var UKRAINIAN_MAP = {
|
||||||
|
'Є':'Ye', 'І':'I', 'Ї':'Yi', 'Ґ':'G', 'є':'ye', 'і':'i', 'ї':'yi', 'ґ':'g'
|
||||||
|
}
|
||||||
var CZECH_MAP = {
|
var CZECH_MAP = {
|
||||||
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
|
'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
|
||||||
'ž':'z'
|
'ž':'z'
|
||||||
@ -51,7 +54,8 @@ ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
|
|||||||
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
|
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
|
||||||
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
|
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
|
||||||
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
|
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
|
||||||
ALL_DOWNCODE_MAPS[5]=CZECH_MAP
|
ALL_DOWNCODE_MAPS[5]=UKRAINIAN_MAP
|
||||||
|
ALL_DOWNCODE_MAPS[6]=CZECH_MAP
|
||||||
|
|
||||||
var Downcoder = new Object();
|
var Downcoder = new Object();
|
||||||
Downcoder.Initialize = function()
|
Downcoder.Initialize = function()
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for result in results %}
|
{% for result in results %}
|
||||||
<tr class="{% cycle row1,row2 %}">{% for item in result %}{{ item }}{% endfor %}</tr>
|
<tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for field in field_list %}
|
{% for field in field_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for year in date_list %}
|
{% for year in date_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ year.year }}/">{{ year.year }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ year.year }}/">{{ year.year }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for month in date_list %}
|
{% for month in date_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ month|date:"M"|lower }}/">{{ month|date:"F" }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ month|date:"M"|lower }}/">{{ month|date:"F" }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for choice in field.choices %}
|
{% for choice in field.choices %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ choice.url }}">{{ choice.label|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ choice.url }}">{{ choice.label|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for field in field_list %}
|
{% for field in field_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object|iriencode }}/">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object|iriencode }}/">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% for model in model_list %}
|
{% for model in model_list %}
|
||||||
<div class="modelgroup {% cycle even,odd %}">
|
<div class="modelgroup {% cycle 'even' 'odd' %}">
|
||||||
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
|
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
|
||||||
<p>
|
<p>
|
||||||
{% for object in model.sample_objects %}
|
{% for object in model.sample_objects %}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in model.objects %}
|
{% for object in model.objects %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<table class="objectinfo">
|
<table class="objectinfo">
|
||||||
{% for field in object.fields %}
|
{% for field in object.fields %}
|
||||||
<tr class="{% cycle odd,even %}">
|
<tr class="{% cycle 'odd' 'even' %}">
|
||||||
<th>{{ field.field.verbose_name|capfirst }}</th>
|
<th>{{ field.field.verbose_name|capfirst }}</th>
|
||||||
<td>
|
<td>
|
||||||
{% if field.urls %}
|
{% if field.urls %}
|
||||||
@ -29,7 +29,7 @@
|
|||||||
{% if related_object.object_list %}
|
{% if related_object.object_list %}
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in related_object.object_list %}
|
{% for object in related_object.object_list %}
|
||||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
0
django/contrib/localflavor/ar/__init__.py
Normal file
0
django/contrib/localflavor/ar/__init__.py
Normal file
36
django/contrib/localflavor/ar/ar_provinces.py
Normal file
36
django/contrib/localflavor/ar/ar_provinces.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
A list of Argentinean provinces and autonomous cities as `choices` in a
|
||||||
|
formfield. From
|
||||||
|
http://www.argentina.gov.ar/argentina/portal/paginas.dhtml?pagina=425
|
||||||
|
|
||||||
|
This exists in this standalone file so that it's only imported into memory
|
||||||
|
when explicitly needed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
PROVINCE_CHOICES = (
|
||||||
|
('B', u'Buenos Aires'),
|
||||||
|
('K', u'Catamarca'),
|
||||||
|
('H', u'Chaco'),
|
||||||
|
('U', u'Chubut'),
|
||||||
|
('C', u'Ciudad Autónoma de Buenos Aires'),
|
||||||
|
('X', u'Córdoba'),
|
||||||
|
('W', u'Corrientes'),
|
||||||
|
('E', u'Entre Ríos'),
|
||||||
|
('P', u'Formosa'),
|
||||||
|
('Y', u'Jujuy'),
|
||||||
|
('L', u'La Pampa'),
|
||||||
|
('F', u'La Rioja'),
|
||||||
|
('M', u'Mendoza'),
|
||||||
|
('N', u'Misiones'),
|
||||||
|
('Q', u'Neuquén'),
|
||||||
|
('R', u'Río Negro'),
|
||||||
|
('A', u'Salta'),
|
||||||
|
('J', u'San Juan'),
|
||||||
|
('D', u'San Luis'),
|
||||||
|
('Z', u'Santa Cruz'),
|
||||||
|
('S', u'Santa Fe'),
|
||||||
|
('G', u'Santiago del Estero'),
|
||||||
|
('V', u'Tierra del Fuego, Antártida e Islas del Atlántico Sur'),
|
||||||
|
('T', u'Tucumán'),
|
||||||
|
)
|
105
django/contrib/localflavor/ar/forms.py
Normal file
105
django/contrib/localflavor/ar/forms.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
AR-specific Form helpers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.newforms import ValidationError
|
||||||
|
from django.newforms.fields import RegexField, CharField, Select, EMPTY_VALUES
|
||||||
|
from django.utils.encoding import smart_unicode
|
||||||
|
from django.utils.translation import ugettext
|
||||||
|
import re
|
||||||
|
|
||||||
|
class ARProvinceSelect(Select):
|
||||||
|
"""
|
||||||
|
A Select widget that uses a list of Argentinean provinces/autonomous cities
|
||||||
|
as its choices.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
from ar_provinces import PROVINCE_CHOICES
|
||||||
|
super(ARProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
|
||||||
|
|
||||||
|
class ARPostalCodeField(RegexField):
|
||||||
|
"""
|
||||||
|
A field that accepts a `classic´ NNNN Postal Code or a CPA.
|
||||||
|
|
||||||
|
See http://www.correoargentino.com.ar/consulta_cpa/home.php
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ARPostalCodeField, self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$',
|
||||||
|
min_length=4, max_length=8,
|
||||||
|
error_message=ugettext("Enter a postal code in the format NNNN or ANNNNAAA."),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
value = super(ARPostalCodeField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
if len(value) not in (4, 8):
|
||||||
|
raise ValidationError(ugettext("Enter a postal code in the format NNNN or ANNNNAAA."))
|
||||||
|
if len(value) == 8:
|
||||||
|
return u'%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper())
|
||||||
|
return value
|
||||||
|
|
||||||
|
class ARDNIField(CharField):
|
||||||
|
"""
|
||||||
|
A field that validates `Documento Nacional de Identidad´ (DNI) numbers.
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ARDNIField, self).__init__(max_length=10, min_length=7, *args,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Value can be a string either in the [X]X.XXX.XXX or [X]XXXXXXX formats.
|
||||||
|
"""
|
||||||
|
value = super(ARDNIField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
if not value.isdigit():
|
||||||
|
value = value.replace('.', '')
|
||||||
|
if not value.isdigit():
|
||||||
|
raise ValidationError(ugettext("This field requires only numbers."))
|
||||||
|
if len(value) not in (7, 8):
|
||||||
|
raise ValidationError(
|
||||||
|
ugettext("This field requires 7 or 8 digits."))
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
class ARCUITField(RegexField):
|
||||||
|
"""
|
||||||
|
This field validates a CUIT (Código Único de Identificación Tributaria). A
|
||||||
|
CUIT is of the form XX-XXXXXXXX-V. The last digit is a check digit.
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ARCUITField, self).__init__(r'^\d{2}-?\d{8}-?\d$',
|
||||||
|
error_message=ugettext('Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'),
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
"""
|
||||||
|
Value can be either a string in the format XX-XXXXXXXX-X or an
|
||||||
|
11-digit number.
|
||||||
|
"""
|
||||||
|
value = super(ARCUITField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
return u''
|
||||||
|
value, cd = self._canon(value)
|
||||||
|
if self._calc_cd(value) != cd:
|
||||||
|
raise ValidationError(ugettext("Invalid CUIT."))
|
||||||
|
return self._format(value, cd)
|
||||||
|
|
||||||
|
def _canon(self, cuit):
|
||||||
|
cuit = cuit.replace('-', '')
|
||||||
|
return cuit[:-1], cuit[-1]
|
||||||
|
|
||||||
|
def _calc_cd(self, cuit):
|
||||||
|
mults = (5, 4, 3, 2, 7, 6, 5, 4, 3, 2)
|
||||||
|
tmp = sum([m * int(cuit[idx]) for idx, m in enumerate(mults)])
|
||||||
|
return str(11 - tmp % 11)
|
||||||
|
|
||||||
|
def _format(self, cuit, check_digit=None):
|
||||||
|
if check_digit == None:
|
||||||
|
check_digit = cuit[-1]
|
||||||
|
cuit = cuit[:-1]
|
||||||
|
return u'%s-%s-%s' % (cuit[:2], cuit[2:], check_digit)
|
||||||
|
|
@ -20,6 +20,7 @@ class ObjectPaginator(object):
|
|||||||
self.num_per_page = num_per_page
|
self.num_per_page = num_per_page
|
||||||
self.orphans = orphans
|
self.orphans = orphans
|
||||||
self._hits = self._pages = None
|
self._hits = self._pages = None
|
||||||
|
self._page_range = None
|
||||||
|
|
||||||
def validate_page_number(self, page_number):
|
def validate_page_number(self, page_number):
|
||||||
try:
|
try:
|
||||||
@ -83,6 +84,16 @@ class ObjectPaginator(object):
|
|||||||
hits = 0
|
hits = 0
|
||||||
self._pages = hits // self.num_per_page + 1
|
self._pages = hits // self.num_per_page + 1
|
||||||
return self._pages
|
return self._pages
|
||||||
|
|
||||||
|
def _get_page_range(self):
|
||||||
|
"""
|
||||||
|
Returns a 1-based range of pages for iterating through within
|
||||||
|
a template for loop.
|
||||||
|
"""
|
||||||
|
if self._page_range is None:
|
||||||
|
self._page_range = range(1, self._pages + 1)
|
||||||
|
return self._page_range
|
||||||
|
|
||||||
hits = property(_get_hits)
|
hits = property(_get_hits)
|
||||||
pages = property(_get_pages)
|
pages = property(_get_pages)
|
||||||
|
page_range = property(_get_page_range)
|
||||||
|
@ -855,6 +855,7 @@ class ImageField(FileField):
|
|||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'form_class': forms.ImageField}
|
defaults = {'form_class': forms.ImageField}
|
||||||
|
defaults.update(kwargs)
|
||||||
return super(ImageField, self).formfield(**defaults)
|
return super(ImageField, self).formfield(**defaults)
|
||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
|
@ -335,12 +335,6 @@ class EmailField(RegexField):
|
|||||||
RegexField.__init__(self, email_re, max_length, min_length,
|
RegexField.__init__(self, email_re, max_length, min_length,
|
||||||
ugettext(u'Enter a valid e-mail address.'), *args, **kwargs)
|
ugettext(u'Enter a valid e-mail address.'), *args, **kwargs)
|
||||||
|
|
||||||
url_re = re.compile(
|
|
||||||
r'^https?://' # http:// or https://
|
|
||||||
r'(?:[A-Z0-9-]+\.)+[A-Z]{2,6}' # domain
|
|
||||||
r'(?::\d+)?' # optional port
|
|
||||||
r'(?:/?|/\S+)$', re.IGNORECASE)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
|
URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
|
||||||
@ -399,6 +393,14 @@ class ImageField(FileField):
|
|||||||
raise ValidationError(ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."))
|
raise ValidationError(ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
url_re = re.compile(
|
||||||
|
r'^https?://' # http:// or https://
|
||||||
|
r'(?:(?:[A-Z0-9-]+\.)+[A-Z]{2,6}|' #domain...
|
||||||
|
r'localhost|' #localhost...
|
||||||
|
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
|
||||||
|
r'(?::\d+)?' # optional port
|
||||||
|
r'(?:/?|/\S+)$', re.IGNORECASE)
|
||||||
|
|
||||||
class URLField(RegexField):
|
class URLField(RegexField):
|
||||||
def __init__(self, max_length=None, min_length=None, verify_exists=False,
|
def __init__(self, max_length=None, min_length=None, verify_exists=False,
|
||||||
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
|
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
|
||||||
|
@ -57,13 +57,15 @@ class BaseForm(StrAndUnicode):
|
|||||||
# class is different than Form. See the comments by the Form class for more
|
# class is different than Form. See the comments by the Form class for more
|
||||||
# information. Any improvements to the form API should be made to *this*
|
# information. Any improvements to the form API should be made to *this*
|
||||||
# class, not to the Form class.
|
# class, not to the Form class.
|
||||||
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None):
|
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
|
||||||
|
initial=None, error_class=ErrorList):
|
||||||
self.is_bound = data is not None or files is not None
|
self.is_bound = data is not None or files is not None
|
||||||
self.data = data or {}
|
self.data = data or {}
|
||||||
self.files = files or {}
|
self.files = files or {}
|
||||||
self.auto_id = auto_id
|
self.auto_id = auto_id
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.initial = initial or {}
|
self.initial = initial or {}
|
||||||
|
self.error_class = error_class
|
||||||
self._errors = None # Stores the errors after clean() has been called.
|
self._errors = None # Stores the errors after clean() has been called.
|
||||||
|
|
||||||
# The base_fields class attribute is the *class-wide* definition of
|
# The base_fields class attribute is the *class-wide* definition of
|
||||||
@ -117,7 +119,7 @@ class BaseForm(StrAndUnicode):
|
|||||||
output, hidden_fields = [], []
|
output, hidden_fields = [], []
|
||||||
for name, field in self.fields.items():
|
for name, field in self.fields.items():
|
||||||
bf = BoundField(self, field, name)
|
bf = BoundField(self, field, name)
|
||||||
bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
||||||
if bf.is_hidden:
|
if bf.is_hidden:
|
||||||
if bf_errors:
|
if bf_errors:
|
||||||
top_errors.extend(['(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
top_errors.extend(['(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
||||||
@ -168,7 +170,7 @@ class BaseForm(StrAndUnicode):
|
|||||||
field -- i.e., from Form.clean(). Returns an empty ErrorList if there
|
field -- i.e., from Form.clean(). Returns an empty ErrorList if there
|
||||||
are none.
|
are none.
|
||||||
"""
|
"""
|
||||||
return self.errors.get(NON_FIELD_ERRORS, ErrorList())
|
return self.errors.get(NON_FIELD_ERRORS, self.error_class())
|
||||||
|
|
||||||
def full_clean(self):
|
def full_clean(self):
|
||||||
"""
|
"""
|
||||||
@ -241,7 +243,7 @@ class BoundField(StrAndUnicode):
|
|||||||
Returns an ErrorList for this field. Returns an empty ErrorList
|
Returns an ErrorList for this field. Returns an empty ErrorList
|
||||||
if there are none.
|
if there are none.
|
||||||
"""
|
"""
|
||||||
return self.form.errors.get(self.name, ErrorList())
|
return self.form.errors.get(self.name, self.form.error_class())
|
||||||
errors = property(_errors)
|
errors = property(_errors)
|
||||||
|
|
||||||
def as_widget(self, widget=None, attrs=None):
|
def as_widget(self, widget=None, attrs=None):
|
||||||
|
@ -30,6 +30,7 @@ class CycleNode(Node):
|
|||||||
def render(self, context):
|
def render(self, context):
|
||||||
self.counter += 1
|
self.counter += 1
|
||||||
value = self.cyclevars[self.counter % self.cyclevars_len]
|
value = self.cyclevars[self.counter % self.cyclevars_len]
|
||||||
|
value = resolve_variable(value, context)
|
||||||
if self.variable_name:
|
if self.variable_name:
|
||||||
context[self.variable_name] = value
|
context[self.variable_name] = value
|
||||||
return value
|
return value
|
||||||
@ -403,7 +404,7 @@ def cycle(parser, token):
|
|||||||
the loop::
|
the loop::
|
||||||
|
|
||||||
{% for o in some_list %}
|
{% for o in some_list %}
|
||||||
<tr class="{% cycle row1,row2 %}">
|
<tr class="{% cycle 'row1' 'row2' %}">
|
||||||
...
|
...
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -411,16 +412,17 @@ def cycle(parser, token):
|
|||||||
Outside of a loop, give the values a unique name the first time you call
|
Outside of a loop, give the values a unique name the first time you call
|
||||||
it, then use that name each sucessive time through::
|
it, then use that name each sucessive time through::
|
||||||
|
|
||||||
<tr class="{% cycle row1,row2,row3 as rowcolors %}">...</tr>
|
<tr class="{% cycle 'row1' 'row2' 'row3' as rowcolors %}">...</tr>
|
||||||
<tr class="{% cycle rowcolors %}">...</tr>
|
<tr class="{% cycle rowcolors %}">...</tr>
|
||||||
<tr class="{% cycle rowcolors %}">...</tr>
|
<tr class="{% cycle rowcolors %}">...</tr>
|
||||||
|
|
||||||
You can use any number of values, seperated by commas. Make sure not to
|
You can use any number of values, seperated by spaces. Commas can also
|
||||||
put spaces between the values -- only commas.
|
be used to separate values; if a comma is used, the cycle values are
|
||||||
|
interpreted as literal strings.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Note: This returns the exact same node on each {% cycle name %} call; that
|
# Note: This returns the exact same node on each {% cycle name %} call; that
|
||||||
# is, the node object returned from {% cycle a,b,c as name %} and the one
|
# is, the node object returned from {% cycle a b c as name %} and the one
|
||||||
# returned from {% cycle name %} are the exact same object. This shouldn't
|
# returned from {% cycle name %} are the exact same object. This shouldn't
|
||||||
# cause problems (heh), but if it does, now you know.
|
# cause problems (heh), but if it does, now you know.
|
||||||
#
|
#
|
||||||
@ -429,40 +431,34 @@ def cycle(parser, token):
|
|||||||
# a global variable, which would make cycle names have to be unique across
|
# a global variable, which would make cycle names have to be unique across
|
||||||
# *all* templates.
|
# *all* templates.
|
||||||
|
|
||||||
args = token.contents.split()
|
args = token.split_contents()
|
||||||
|
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
raise TemplateSyntaxError("'Cycle' statement requires at least two arguments")
|
raise TemplateSyntaxError("'cycle' tag requires at least two arguments")
|
||||||
|
|
||||||
elif len(args) == 2 and "," in args[1]:
|
if ',' in args[1]:
|
||||||
# {% cycle a,b,c %}
|
# Backwards compatibility: {% cycle a,b %} or {% cycle a,b as foo %}
|
||||||
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
|
# case.
|
||||||
return CycleNode(cyclevars)
|
args[1:2] = ['"%s"' % arg for arg in args[1].split(",")]
|
||||||
# {% cycle name %}
|
|
||||||
|
|
||||||
elif len(args) == 2:
|
if len(args) == 2:
|
||||||
|
# {% cycle foo %} case
|
||||||
name = args[1]
|
name = args[1]
|
||||||
if not hasattr(parser, '_namedCycleNodes'):
|
if not hasattr(parser, '_namedCycleNodes'):
|
||||||
raise TemplateSyntaxError("No named cycles in template: '%s' is not defined" % name)
|
raise TemplateSyntaxError("No named cycles in template: '%s' is not defined" % name)
|
||||||
if name not in parser._namedCycleNodes:
|
if not name in parser._namedCycleNodes:
|
||||||
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
|
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
|
||||||
return parser._namedCycleNodes[name]
|
return parser._namedCycleNodes[name]
|
||||||
|
|
||||||
elif len(args) == 4:
|
if len(args) > 4 and args[-2] == 'as':
|
||||||
# {% cycle a,b,c as name %}
|
name = args[-1]
|
||||||
if args[2] != 'as':
|
node = CycleNode(args[1:-2], name)
|
||||||
raise TemplateSyntaxError("Second 'cycle' argument must be 'as'")
|
|
||||||
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
|
|
||||||
name = args[3]
|
|
||||||
node = CycleNode(cyclevars, name)
|
|
||||||
|
|
||||||
if not hasattr(parser, '_namedCycleNodes'):
|
if not hasattr(parser, '_namedCycleNodes'):
|
||||||
parser._namedCycleNodes = {}
|
parser._namedCycleNodes = {}
|
||||||
|
|
||||||
parser._namedCycleNodes[name] = node
|
parser._namedCycleNodes[name] = node
|
||||||
return node
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
|
node = CycleNode(args[1:])
|
||||||
|
return node
|
||||||
cycle = register.tag(cycle)
|
cycle = register.tag(cycle)
|
||||||
|
|
||||||
def debug(parser, token):
|
def debug(parser, token):
|
||||||
|
@ -39,6 +39,8 @@ def object_list(request, queryset, paginate_by=None, page=None,
|
|||||||
first_on_page
|
first_on_page
|
||||||
the result number of the first object in the
|
the result number of the first object in the
|
||||||
object_list (1-indexed)
|
object_list (1-indexed)
|
||||||
|
page_range:
|
||||||
|
A list of the page numbers (1-indexed).
|
||||||
"""
|
"""
|
||||||
if extra_context is None: extra_context = {}
|
if extra_context is None: extra_context = {}
|
||||||
queryset = queryset._clone()
|
queryset = queryset._clone()
|
||||||
@ -47,10 +49,17 @@ def object_list(request, queryset, paginate_by=None, page=None,
|
|||||||
if not page:
|
if not page:
|
||||||
page = request.GET.get('page', 1)
|
page = request.GET.get('page', 1)
|
||||||
try:
|
try:
|
||||||
page = int(page)
|
page_number = int(page)
|
||||||
object_list = paginator.get_page(page - 1)
|
except ValueError:
|
||||||
except (InvalidPage, ValueError):
|
if page == 'last':
|
||||||
if page == 1 and allow_empty:
|
page_number = paginator.pages
|
||||||
|
else:
|
||||||
|
# Page is not 'last', nor can it be converted to an int
|
||||||
|
raise Http404
|
||||||
|
try:
|
||||||
|
object_list = paginator.get_page(page_number - 1)
|
||||||
|
except InvalidPage:
|
||||||
|
if page_number == 1 and allow_empty:
|
||||||
object_list = []
|
object_list = []
|
||||||
else:
|
else:
|
||||||
raise Http404
|
raise Http404
|
||||||
@ -58,15 +67,16 @@ def object_list(request, queryset, paginate_by=None, page=None,
|
|||||||
'%s_list' % template_object_name: object_list,
|
'%s_list' % template_object_name: object_list,
|
||||||
'is_paginated': paginator.pages > 1,
|
'is_paginated': paginator.pages > 1,
|
||||||
'results_per_page': paginate_by,
|
'results_per_page': paginate_by,
|
||||||
'has_next': paginator.has_next_page(page - 1),
|
'has_next': paginator.has_next_page(page_number - 1),
|
||||||
'has_previous': paginator.has_previous_page(page - 1),
|
'has_previous': paginator.has_previous_page(page_number - 1),
|
||||||
'page': page,
|
'page': page_number,
|
||||||
'next': page + 1,
|
'next': page_number + 1,
|
||||||
'previous': page - 1,
|
'previous': page_number - 1,
|
||||||
'last_on_page': paginator.last_on_page(page - 1),
|
'last_on_page': paginator.last_on_page(page_number - 1),
|
||||||
'first_on_page': paginator.first_on_page(page - 1),
|
'first_on_page': paginator.first_on_page(page_number - 1),
|
||||||
'pages': paginator.pages,
|
'pages': paginator.pages,
|
||||||
'hits' : paginator.hits,
|
'hits' : paginator.hits,
|
||||||
|
'page_range' : paginator.page_range
|
||||||
}, context_processors)
|
}, context_processors)
|
||||||
else:
|
else:
|
||||||
c = RequestContext(request, {
|
c = RequestContext(request, {
|
||||||
|
@ -688,9 +688,8 @@ A page representing a list of objects.
|
|||||||
* ``paginate_by``: An integer specifying how many objects should be
|
* ``paginate_by``: An integer specifying how many objects should be
|
||||||
displayed per page. If this is given, the view will paginate objects with
|
displayed per page. If this is given, the view will paginate objects with
|
||||||
``paginate_by`` objects per page. The view will expect either a ``page``
|
``paginate_by`` objects per page. The view will expect either a ``page``
|
||||||
query string parameter (via ``GET``) containing a 1-based page
|
query string parameter (via ``GET``) or a ``page`` variable specified in
|
||||||
number, or a ``page`` variable specified in the URLconf. See
|
the URLconf. See "Notes on pagination" below.
|
||||||
"Notes on pagination" below.
|
|
||||||
|
|
||||||
* ``template_name``: The full name of a template to use in rendering the
|
* ``template_name``: The full name of a template to use in rendering the
|
||||||
page. This lets you override the default template name (see below).
|
page. This lets you override the default template name (see below).
|
||||||
@ -765,6 +764,9 @@ If the results are paginated, the context will contain these extra variables:
|
|||||||
* ``hits``: The total number of objects across *all* pages, not just this
|
* ``hits``: The total number of objects across *all* pages, not just this
|
||||||
page.
|
page.
|
||||||
|
|
||||||
|
* ``page_range``: A list of the page numbers that are available. This
|
||||||
|
is 1-based.
|
||||||
|
|
||||||
Notes on pagination
|
Notes on pagination
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -777,12 +779,25 @@ specify the page number in the URL in one of two ways:
|
|||||||
(r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
|
(r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
|
||||||
|
|
||||||
* Pass the page number via the ``page`` query-string parameter. For
|
* Pass the page number via the ``page`` query-string parameter. For
|
||||||
example, a URL would look like this:
|
example, a URL would look like this::
|
||||||
|
|
||||||
/objects/?page=3
|
/objects/?page=3
|
||||||
|
|
||||||
In both cases, ``page`` is 1-based, not 0-based, so the first page would be
|
* To loop over all the available page numbers, use the ``page_range``
|
||||||
represented as page ``1``.
|
variable. You can iterate over the list provided by ``page_range``
|
||||||
|
to create a link to every page of results.
|
||||||
|
|
||||||
|
These values and lists are is 1-based, not 0-based, so the first page would be
|
||||||
|
represented as page ``1``. As a special case, you are also permitted to use
|
||||||
|
``last`` as a value for ``page``::
|
||||||
|
|
||||||
|
/objects/?page=last
|
||||||
|
|
||||||
|
This allows you to access the final page of results without first having to
|
||||||
|
determine how many pages there are.
|
||||||
|
|
||||||
|
Note that ``page`` *must* be either a valid page number or the value ``last``;
|
||||||
|
any other value for ``page`` will result in a 404 error.
|
||||||
|
|
||||||
``django.views.generic.list_detail.object_detail``
|
``django.views.generic.list_detail.object_detail``
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
@ -554,6 +554,29 @@ method you're using::
|
|||||||
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
|
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
|
||||||
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
|
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
|
||||||
|
|
||||||
|
Customizing the error list format
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
By default, forms use ``django.newforms.util.ErrorList`` to format validation
|
||||||
|
errors. If you'd like to use an alternate class for displaying errors, you can
|
||||||
|
pass that in at construction time::
|
||||||
|
|
||||||
|
>>> from django.newforms.util import ErrorList
|
||||||
|
>>> class DivErrorList(ErrorList):
|
||||||
|
... def __unicode__(self):
|
||||||
|
... return self.as_divs()
|
||||||
|
... def as_divs(self):
|
||||||
|
... if not self: return u''
|
||||||
|
... return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
|
||||||
|
>>> f = ContactForm(data, auto_id=False, error_class=DivErrorList)
|
||||||
|
>>> f.as_p()
|
||||||
|
<div class="errorlist"><div class="error">This field is required.</div></div>
|
||||||
|
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
|
||||||
|
<p>Message: <input type="text" name="message" value="Hi there" /></p>
|
||||||
|
<div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
|
||||||
|
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
|
||||||
|
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
|
||||||
|
|
||||||
More granular output
|
More granular output
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -1893,6 +1916,17 @@ 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
|
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.
|
this example has an ``else`` clause that implements the default behavior.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
The field that is passed into the ``formfield_callback`` function in
|
||||||
|
``form_for_model()`` and ``form_for_instance`` is the field instance from
|
||||||
|
your model's class. You **must not** alter that object at all; treat it
|
||||||
|
as read-only!
|
||||||
|
|
||||||
|
If you make any alterations to that object, it will affect any future
|
||||||
|
users of the model class, because you will have changed the field object
|
||||||
|
used to construct the class. This is almost certainly what you don't want
|
||||||
|
to have happen.
|
||||||
|
|
||||||
Finding the model associated with a form
|
Finding the model associated with a form
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -183,6 +183,9 @@ subclass of dictionary. Exceptions are outlined here:
|
|||||||
|
|
||||||
* ``__getitem__(key)`` -- Returns the value for the given key. If the key
|
* ``__getitem__(key)`` -- Returns the value for the given key. If the key
|
||||||
has more than one value, ``__getitem__()`` returns the last value.
|
has more than one value, ``__getitem__()`` returns the last value.
|
||||||
|
Raises ``django.utils.datastructure.MultiValueDictKeyError`` if the key
|
||||||
|
does not exist (fortunately, this is a subclass of Python's standard
|
||||||
|
``KeyError``, so you can stick to catching ``KeyError``).
|
||||||
|
|
||||||
* ``__setitem__(key, value)`` -- Sets the given key to ``[value]``
|
* ``__setitem__(key, value)`` -- Sets the given key to ``[value]``
|
||||||
(a Python list whose single element is ``value``). Note that this, as
|
(a Python list whose single element is ``value``). Note that this, as
|
||||||
|
@ -316,6 +316,9 @@ Here's how Django uses the sites framework:
|
|||||||
* The shortcut view (``django.views.defaults.shortcut``) uses the domain of
|
* The shortcut view (``django.views.defaults.shortcut``) uses the domain of
|
||||||
the current ``Site`` object when calculating an object's URL.
|
the current ``Site`` object when calculating an object's URL.
|
||||||
|
|
||||||
|
* In the admin framework, the ''view on site'' link uses the current
|
||||||
|
``Site`` to work out the domain for the site that it will redirect to.
|
||||||
|
|
||||||
.. _redirects framework: ../redirects/
|
.. _redirects framework: ../redirects/
|
||||||
.. _flatpages framework: ../flatpages/
|
.. _flatpages framework: ../flatpages/
|
||||||
.. _syndication framework: ../syndication_feeds/
|
.. _syndication framework: ../syndication_feeds/
|
||||||
|
@ -366,25 +366,36 @@ Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
|
|||||||
cycle
|
cycle
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
Cycle among the given strings each time this tag is encountered.
|
**Changed in Django development version**
|
||||||
|
Cycle among the given strings or variables each time this tag is encountered.
|
||||||
|
|
||||||
Within a loop, cycles among the given strings each time through the loop::
|
Within a loop, cycles among the given strings/variables each time through the
|
||||||
|
loop::
|
||||||
|
|
||||||
{% for o in some_list %}
|
{% for o in some_list %}
|
||||||
<tr class="{% cycle row1,row2 %}">
|
<tr class="{% cycle 'row1' 'row2' rowvar %}">
|
||||||
...
|
...
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
Outside of a loop, give the values a unique name the first time you call it,
|
Outside of a loop, give the values a unique name the first time you call it,
|
||||||
then use that name each successive time through::
|
then use that name each successive time through::
|
||||||
|
|
||||||
<tr class="{% cycle row1,row2,row3 as rowcolors %}">...</tr>
|
<tr class="{% cycle 'row1' 'row2' rowvar as rowcolors %}">...</tr>
|
||||||
<tr class="{% cycle rowcolors %}">...</tr>
|
<tr class="{% cycle rowcolors %}">...</tr>
|
||||||
<tr class="{% cycle rowcolors %}">...</tr>
|
<tr class="{% cycle rowcolors %}">...</tr>
|
||||||
|
|
||||||
You can use any number of values, separated by commas. Make sure not to put
|
You can use any number of values, separated by spaces. Values enclosed in
|
||||||
spaces between the values -- only commas.
|
single (') or double quotes (") are treated as string literals, while values
|
||||||
|
without quotes are assumed to refer to context variables.
|
||||||
|
|
||||||
|
You can also separate values with commas::
|
||||||
|
|
||||||
|
{% cycle row1,row2,row3 %}
|
||||||
|
|
||||||
|
In this syntax, each value will be interpreted as literal text. The
|
||||||
|
comma-based syntax exists for backwards-compatibility, and should not be
|
||||||
|
used for new projects.
|
||||||
|
|
||||||
debug
|
debug
|
||||||
~~~~~
|
~~~~~
|
||||||
|
@ -642,7 +642,23 @@ your function. Example::
|
|||||||
"Converts a string into all lowercase"
|
"Converts a string into all lowercase"
|
||||||
return value.lower()
|
return value.lower()
|
||||||
|
|
||||||
When you've written your filter definition, you need to register it with
|
Template filters which expect strings
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If you're writing a template filter which only expects a string as the first
|
||||||
|
argument, you should use the included decorator ``stringfilter``. This will
|
||||||
|
convert an object to it's string value before being passed to your function::
|
||||||
|
|
||||||
|
from django.template.defaultfilters import stringfilter
|
||||||
|
|
||||||
|
@stringfilter
|
||||||
|
def lower(value):
|
||||||
|
return value.lower()
|
||||||
|
|
||||||
|
Registering a custom filters
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Once you've written your filter definition, you need to register it with
|
||||||
your ``Library`` instance, to make it available to Django's template language::
|
your ``Library`` instance, to make it available to Django's template language::
|
||||||
|
|
||||||
register.filter('cut', cut)
|
register.filter('cut', cut)
|
||||||
@ -658,28 +674,18 @@ If you're using Python 2.4 or above, you can use ``register.filter()`` as a
|
|||||||
decorator instead::
|
decorator instead::
|
||||||
|
|
||||||
@register.filter(name='cut')
|
@register.filter(name='cut')
|
||||||
|
@stringfilter
|
||||||
def cut(value, arg):
|
def cut(value, arg):
|
||||||
return value.replace(arg, '')
|
return value.replace(arg, '')
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
|
@stringfilter
|
||||||
def lower(value):
|
def lower(value):
|
||||||
return value.lower()
|
return value.lower()
|
||||||
|
|
||||||
If you leave off the ``name`` argument, as in the second example above, Django
|
If you leave off the ``name`` argument, as in the second example above, Django
|
||||||
will use the function's name as the filter name.
|
will use the function's name as the filter name.
|
||||||
|
|
||||||
Template filters which expect strings
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
If you are writing a template filter which only expects a string as the first
|
|
||||||
argument, you should use the included decorator ``stringfilter`` which will convert
|
|
||||||
an object to it's string value before being passed to your function::
|
|
||||||
|
|
||||||
from django.template.defaultfilters import stringfilter
|
|
||||||
|
|
||||||
@stringfilter
|
|
||||||
def lower(value):
|
|
||||||
return value.lower()
|
|
||||||
|
|
||||||
Writing custom template tags
|
Writing custom template tags
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
@ -569,8 +569,8 @@ Testing responses
|
|||||||
|
|
||||||
The ``get()`` and ``post()`` methods both return a ``Response`` object. This
|
The ``get()`` and ``post()`` methods both return a ``Response`` object. This
|
||||||
``Response`` object is *not* the same as the ``HttpResponse`` object returned
|
``Response`` object is *not* the same as the ``HttpResponse`` object returned
|
||||||
Django views; this object is simpler and has some additional data useful for
|
Django views; the test response object has some additional data useful for
|
||||||
tests.
|
test code to verify.
|
||||||
|
|
||||||
Specifically, a ``Response`` object has the following attributes:
|
Specifically, a ``Response`` object has the following attributes:
|
||||||
|
|
||||||
@ -582,7 +582,7 @@ Specifically, a ``Response`` object has the following attributes:
|
|||||||
|
|
||||||
``content`` The body of the response, as a string. This is the final
|
``content`` The body of the response, as a string. This is the final
|
||||||
page content as rendered by the view, or any error
|
page content as rendered by the view, or any error
|
||||||
message (such as the URL for a 302 redirect).
|
message.
|
||||||
|
|
||||||
``context`` The template ``Context`` instance that was used to render
|
``context`` The template ``Context`` instance that was used to render
|
||||||
the template that produced the response content.
|
the template that produced the response content.
|
||||||
@ -591,6 +591,8 @@ Specifically, a ``Response`` object has the following attributes:
|
|||||||
``context`` will be a list of ``Context``
|
``context`` will be a list of ``Context``
|
||||||
objects, in the order in which they were rendered.
|
objects, in the order in which they were rendered.
|
||||||
|
|
||||||
|
``headers`` The HTTP headers of the response. This is a dictionary.
|
||||||
|
|
||||||
``request`` The request data that stimulated the response.
|
``request`` The request data that stimulated the response.
|
||||||
|
|
||||||
``status_code`` The HTTP status of the response, as an integer. See
|
``status_code`` The HTTP status of the response, as an integer. See
|
||||||
|
@ -77,4 +77,8 @@ True
|
|||||||
>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1)
|
>>> paginator = ObjectPaginator(Article.objects.all(), 10, orphans=1)
|
||||||
>>> paginator.pages
|
>>> paginator.pages
|
||||||
2
|
2
|
||||||
|
|
||||||
|
# The paginator can provide a list of all available pages
|
||||||
|
>>> paginator.page_range
|
||||||
|
[1, 2]
|
||||||
"""}
|
"""}
|
||||||
|
@ -1514,4 +1514,294 @@ ValidationError: [u'Enter a valid SoFi number']
|
|||||||
>>> s = NLProvinceSelect()
|
>>> s = NLProvinceSelect()
|
||||||
>>> s.render('provinces', 'OV')
|
>>> s.render('provinces', 'OV')
|
||||||
u'<select name="provinces">\n<option value="DR">Drente</option>\n<option value="FL">Flevoland</option>\n<option value="FR">Friesland</option>\n<option value="GL">Gelderland</option>\n<option value="GR">Groningen</option>\n<option value="LB">Limburg</option>\n<option value="NB">Noord-Brabant</option>\n<option value="NH">Noord-Holland</option>\n<option value="OV" selected="selected">Overijssel</option>\n<option value="UT">Utrecht</option>\n<option value="ZE">Zeeland</option>\n<option value="ZH">Zuid-Holland</option>\n</select>'
|
u'<select name="provinces">\n<option value="DR">Drente</option>\n<option value="FL">Flevoland</option>\n<option value="FR">Friesland</option>\n<option value="GL">Gelderland</option>\n<option value="GR">Groningen</option>\n<option value="LB">Limburg</option>\n<option value="NB">Noord-Brabant</option>\n<option value="NH">Noord-Holland</option>\n<option value="OV" selected="selected">Overijssel</option>\n<option value="UT">Utrecht</option>\n<option value="ZE">Zeeland</option>\n<option value="ZH">Zuid-Holland</option>\n</select>'
|
||||||
|
|
||||||
|
# ARProvinceField #############################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.ar.forms import ARProvinceSelect
|
||||||
|
>>> f = ARProvinceSelect()
|
||||||
|
>>> f.render('provincias', 'A')
|
||||||
|
u'<select name="provincias">\n<option value="B">Buenos Aires</option>\n<option value="K">Catamarca</option>\n<option value="H">Chaco</option>\n<option value="U">Chubut</option>\n<option value="C">Ciudad Aut\xf3noma de Buenos Aires</option>\n<option value="X">C\xf3rdoba</option>\n<option value="W">Corrientes</option>\n<option value="E">Entre R\xedos</option>\n<option value="P">Formosa</option>\n<option value="Y">Jujuy</option>\n<option value="L">La Pampa</option>\n<option value="F">La Rioja</option>\n<option value="M">Mendoza</option>\n<option value="N">Misiones</option>\n<option value="Q">Neuqu\xe9n</option>\n<option value="R">R\xedo Negro</option>\n<option value="A" selected="selected">Salta</option>\n<option value="J">San Juan</option>\n<option value="D">San Luis</option>\n<option value="Z">Santa Cruz</option>\n<option value="S">Santa Fe</option>\n<option value="G">Santiago del Estero</option>\n<option value="V">Tierra del Fuego, Ant\xe1rtida e Islas del Atl\xe1ntico Sur</option>\n<option value="T">Tucum\xe1n</option>\n</select>'
|
||||||
|
|
||||||
|
# ARPostalCodeField ###########################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.ar.forms import ARPostalCodeField
|
||||||
|
>>> f = ARPostalCodeField()
|
||||||
|
>>> f.clean('5000')
|
||||||
|
u'5000'
|
||||||
|
>>> f.clean('C1064AAB')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean('c1064AAB')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean('C1064aab')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean(u'4400')
|
||||||
|
u'4400'
|
||||||
|
>>> f.clean(u'C1064AAB')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean('C1064AABB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
|
||||||
|
>>> f.clean('C1064AA')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean('C106AAB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean('106AAB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean('500')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
|
||||||
|
>>> f.clean('5PPP')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(u'')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ARPostalCodeField(required=False)
|
||||||
|
>>> f.clean('5000')
|
||||||
|
u'5000'
|
||||||
|
>>> f.clean('C1064AAB')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean('c1064AAB')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean('C1064aab')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean(u'4400')
|
||||||
|
u'4400'
|
||||||
|
>>> f.clean(u'C1064AAB')
|
||||||
|
u'C1064AAB'
|
||||||
|
>>> f.clean('C1064AABB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
|
||||||
|
>>> f.clean('C1064AA')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean('C106AAB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean('106AAB')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean('500')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
|
||||||
|
>>> f.clean('5PPP')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(u'')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# ARDNIField ##################################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.ar.forms import ARDNIField
|
||||||
|
>>> f = ARDNIField()
|
||||||
|
>>> f.clean('20123456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('20.123.456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('9123456')
|
||||||
|
u'9123456'
|
||||||
|
>>> f.clean('9.123.456')
|
||||||
|
u'9123456'
|
||||||
|
>>> f.clean(u'20123456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean(u'20.123.456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('20.123456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('101234566')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field requires 7 or 8 digits.']
|
||||||
|
>>> f.clean('W0123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field requires only numbers.']
|
||||||
|
>>> f.clean('10,123,456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field requires only numbers.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(u'')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ARDNIField(required=False)
|
||||||
|
>>> f.clean('20123456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('20.123.456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('9123456')
|
||||||
|
u'9123456'
|
||||||
|
>>> f.clean('9.123.456')
|
||||||
|
u'9123456'
|
||||||
|
>>> f.clean(u'20123456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean(u'20.123.456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('20.123456')
|
||||||
|
u'20123456'
|
||||||
|
>>> f.clean('101234566')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field requires 7 or 8 digits.']
|
||||||
|
>>> f.clean('W0123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field requires only numbers.']
|
||||||
|
>>> f.clean('10,123,456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field requires only numbers.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(u'')
|
||||||
|
u''
|
||||||
|
|
||||||
|
# ARCUITField #################################################################
|
||||||
|
|
||||||
|
>>> from django.contrib.localflavor.ar.forms import ARCUITField
|
||||||
|
>>> f = ARCUITField()
|
||||||
|
>>> f.clean('20-10123456-9')
|
||||||
|
u'20-10123456-9'
|
||||||
|
>>> f.clean(u'20-10123456-9')
|
||||||
|
u'20-10123456-9'
|
||||||
|
>>> f.clean('27-10345678-4')
|
||||||
|
u'27-10345678-4'
|
||||||
|
>>> f.clean('20101234569')
|
||||||
|
u'20-10123456-9'
|
||||||
|
>>> f.clean('27103456784')
|
||||||
|
u'27-10345678-4'
|
||||||
|
>>> f.clean('2-10123456-9')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('210123456-9')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('20-10123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('20-10123456-')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('20-10123456-5')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid CUIT.']
|
||||||
|
>>> f.clean(u'2-10123456-9')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('27-10345678-1')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid CUIT.']
|
||||||
|
>>> f.clean(u'27-10345678-1')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid CUIT.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean(u'')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
|
||||||
|
>>> f = ARCUITField(required=False)
|
||||||
|
>>> f.clean('20-10123456-9')
|
||||||
|
u'20-10123456-9'
|
||||||
|
>>> f.clean(u'20-10123456-9')
|
||||||
|
u'20-10123456-9'
|
||||||
|
>>> f.clean('27-10345678-4')
|
||||||
|
u'27-10345678-4'
|
||||||
|
>>> f.clean('20101234569')
|
||||||
|
u'20-10123456-9'
|
||||||
|
>>> f.clean('27103456784')
|
||||||
|
u'27-10345678-4'
|
||||||
|
>>> f.clean('2-10123456-9')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('210123456-9')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('20-10123456')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('20-10123456-')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('20-10123456-5')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid CUIT.']
|
||||||
|
>>> f.clean(u'2-10123456-9')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
|
||||||
|
>>> f.clean('27-10345678-1')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid CUIT.']
|
||||||
|
>>> f.clean(u'27-10345678-1')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Invalid CUIT.']
|
||||||
|
>>> f.clean(None)
|
||||||
|
u''
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean(u'')
|
||||||
|
u''
|
||||||
"""
|
"""
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from localflavor import localflavor_tests
|
from localflavor import localflavor_tests
|
||||||
from regressions import regression_tests
|
from regressions import regression_tests
|
||||||
|
from util import util_tests
|
||||||
|
|
||||||
form_tests = r"""
|
form_tests = r"""
|
||||||
>>> from django.newforms import *
|
>>> from django.newforms import *
|
||||||
@ -1606,10 +1607,18 @@ ValidationError: [u'This field is required.']
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'This field is required.']
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('http://localhost')
|
||||||
|
u'http://localhost'
|
||||||
>>> f.clean('http://example.com')
|
>>> f.clean('http://example.com')
|
||||||
u'http://example.com'
|
u'http://example.com'
|
||||||
>>> f.clean('http://www.example.com')
|
>>> f.clean('http://www.example.com')
|
||||||
u'http://www.example.com'
|
u'http://www.example.com'
|
||||||
|
>>> f.clean('http://www.example.com:8000/test')
|
||||||
|
u'http://www.example.com:8000/test'
|
||||||
|
>>> f.clean('http://200.8.9.10')
|
||||||
|
u'http://200.8.9.10'
|
||||||
|
>>> f.clean('http://200.8.9.10:8000/test')
|
||||||
|
u'http://200.8.9.10:8000/test'
|
||||||
>>> f.clean('foo')
|
>>> f.clean('foo')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
@ -3794,14 +3803,6 @@ u'1'
|
|||||||
>>> smart_unicode('foo')
|
>>> smart_unicode('foo')
|
||||||
u'foo'
|
u'foo'
|
||||||
|
|
||||||
# flatatt tests
|
|
||||||
>>> from django.newforms.util import flatatt
|
|
||||||
>>> flatatt({'id': "header"})
|
|
||||||
u' id="header"'
|
|
||||||
>>> flatatt({'class': "news", 'title': "Read this"})
|
|
||||||
u' class="news" title="Read this"'
|
|
||||||
>>> flatatt({})
|
|
||||||
u''
|
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# Test accessing errors in clean() #
|
# Test accessing errors in clean() #
|
||||||
@ -3821,12 +3822,38 @@ u''
|
|||||||
True
|
True
|
||||||
>>> f.cleaned_data['username']
|
>>> f.cleaned_data['username']
|
||||||
u'sirrobin'
|
u'sirrobin'
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Test overriding ErrorList in a form #
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
>>> from django.newforms.util import ErrorList
|
||||||
|
>>> class DivErrorList(ErrorList):
|
||||||
|
... def __unicode__(self):
|
||||||
|
... return self.as_divs()
|
||||||
|
... def as_divs(self):
|
||||||
|
... if not self: return u''
|
||||||
|
... return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
|
||||||
|
>>> class CommentForm(Form):
|
||||||
|
... name = CharField(max_length=50, required=False)
|
||||||
|
... email = EmailField()
|
||||||
|
... comment = CharField()
|
||||||
|
>>> data = dict(email='invalid')
|
||||||
|
>>> f = CommentForm(data, auto_id=False, error_class=DivErrorList)
|
||||||
|
>>> print f.as_p()
|
||||||
|
<p>Name: <input type="text" name="name" maxlength="50" /></p>
|
||||||
|
<div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
|
||||||
|
<p>Email: <input type="text" name="email" value="invalid" /></p>
|
||||||
|
<div class="errorlist"><div class="error">This field is required.</div></div>
|
||||||
|
<p>Comment: <input type="text" name="comment" /></p>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__test__ = {
|
__test__ = {
|
||||||
'form_tests': form_tests,
|
'form_tests': form_tests,
|
||||||
'localflavor': localflavor_tests,
|
'localflavor': localflavor_tests,
|
||||||
'regressions': regression_tests,
|
'regressions': regression_tests,
|
||||||
|
'util_tests': util_tests,
|
||||||
}
|
}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
45
tests/regressiontests/forms/util.py
Normal file
45
tests/regressiontests/forms/util.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
"""
|
||||||
|
Tests for newforms/util.py module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
util_tests = r"""
|
||||||
|
>>> from django.newforms.util import *
|
||||||
|
>>> from django.utils.translation import ugettext_lazy
|
||||||
|
|
||||||
|
###########
|
||||||
|
# flatatt #
|
||||||
|
###########
|
||||||
|
|
||||||
|
>>> from django.newforms.util import flatatt
|
||||||
|
>>> flatatt({'id': "header"})
|
||||||
|
u' id="header"'
|
||||||
|
>>> flatatt({'class': "news", 'title': "Read this"})
|
||||||
|
u' class="news" title="Read this"'
|
||||||
|
>>> flatatt({})
|
||||||
|
u''
|
||||||
|
|
||||||
|
###################
|
||||||
|
# ValidationError #
|
||||||
|
###################
|
||||||
|
|
||||||
|
# Can take a string.
|
||||||
|
>>> print ValidationError("There was an error.").messages
|
||||||
|
<ul class="errorlist"><li>There was an error.</li></ul>
|
||||||
|
|
||||||
|
# Can take a unicode string.
|
||||||
|
>>> print ValidationError(u"Not \u03C0.").messages
|
||||||
|
<ul class="errorlist"><li>Not π.</li></ul>
|
||||||
|
|
||||||
|
# Can take a lazy string.
|
||||||
|
>>> print ValidationError(ugettext_lazy("Error.")).messages
|
||||||
|
<ul class="errorlist"><li>Error.</li></ul>
|
||||||
|
|
||||||
|
# Can take a list.
|
||||||
|
>>> print ValidationError(["Error one.", "Error two."]).messages
|
||||||
|
<ul class="errorlist"><li>Error one.</li><li>Error two.</li></ul>
|
||||||
|
|
||||||
|
# Can take a mixture in a list.
|
||||||
|
>>> print ValidationError(["First error.", u"Not \u03C0.", ugettext_lazy("Error.")]).messages
|
||||||
|
<ul class="errorlist"><li>First error.</li><li>Not π.</li><li>Error.</li></ul>
|
||||||
|
"""
|
@ -306,6 +306,14 @@ class Templates(unittest.TestCase):
|
|||||||
'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
|
'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
|
||||||
'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
|
'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
|
||||||
'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'),
|
'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'),
|
||||||
|
'cycle09': ("{% for i in test %}{% cycle a,b %}{{ i }},{% endfor %}", {'test': range(5)}, 'a0,b1,a2,b3,a4,'),
|
||||||
|
# New format:
|
||||||
|
'cycle10': ("{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}", {}, 'ab'),
|
||||||
|
'cycle11': ("{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}", {}, 'abc'),
|
||||||
|
'cycle12': ("{% cycle 'a' 'b' 'c' as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}", {}, 'abca'),
|
||||||
|
'cycle13': ("{% for i in test %}{% cycle 'a' 'b' %}{{ i }},{% endfor %}", {'test': range(5)}, 'a0,b1,a2,b3,a4,'),
|
||||||
|
'cycle14': ("{% cycle one two as foo %}{% cycle foo %}", {'one': '1','two': '2'}, '12'),
|
||||||
|
'cycle13': ("{% for i in test %}{% cycle aye bee %}{{ i }},{% endfor %}", {'test': range(5), 'aye': 'a', 'bee': 'b'}, 'a0,b1,a2,b3,a4,'),
|
||||||
|
|
||||||
### EXCEPTIONS ############################################################
|
### EXCEPTIONS ############################################################
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user