mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Merged to [6190]
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6334 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
fb6a0c8ffa
commit
bf6a46d8ad
1
AUTHORS
1
AUTHORS
@ -246,6 +246,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Brian Ray <http://brianray.chipy.org/>
|
Brian Ray <http://brianray.chipy.org/>
|
||||||
remco@diji.biz
|
remco@diji.biz
|
||||||
rhettg@gmail.com
|
rhettg@gmail.com
|
||||||
|
Matt Riggott
|
||||||
Henrique Romano <onaiort@gmail.com>
|
Henrique Romano <onaiort@gmail.com>
|
||||||
Armin Ronacher
|
Armin Ronacher
|
||||||
Brian Rosner <brosner@gmail.com>
|
Brian Rosner <brosner@gmail.com>
|
||||||
|
Binary file not shown.
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: KBabel 1.11.4\n"
|
"X-Generator: KBabel 1.11.4\n"
|
||||||
"Plural-Forms: nplurals=2; nplurals=n>1;"
|
"Plural-Forms: nplurals=2; plural=n>1;"
|
||||||
|
|
||||||
#: contrib/comments/models.py:67 contrib/comments/models.py:166
|
#: contrib/comments/models.py:67 contrib/comments/models.py:166
|
||||||
msgid "object ID"
|
msgid "object ID"
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
// Core javascript helper functions
|
// Core javascript helper functions
|
||||||
|
|
||||||
|
// basic browser identification & version
|
||||||
|
var isOpera = (navigator.userAgent.indexOf("Opera")>=0) && parseFloat(navigator.appVersion);
|
||||||
|
var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]);
|
||||||
|
|
||||||
// Cross-browser event handlers.
|
// Cross-browser event handlers.
|
||||||
function addEvent(obj, evType, fn) {
|
function addEvent(obj, evType, fn) {
|
||||||
if (obj.addEventListener) {
|
if (obj.addEventListener) {
|
||||||
@ -71,9 +75,13 @@ function findPosX(obj) {
|
|||||||
var curleft = 0;
|
var curleft = 0;
|
||||||
if (obj.offsetParent) {
|
if (obj.offsetParent) {
|
||||||
while (obj.offsetParent) {
|
while (obj.offsetParent) {
|
||||||
curleft += obj.offsetLeft;
|
curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft);
|
||||||
obj = obj.offsetParent;
|
obj = obj.offsetParent;
|
||||||
}
|
}
|
||||||
|
// IE offsetParent does not include the top-level
|
||||||
|
if (isIE && obj.parentElement){
|
||||||
|
curleft += obj.offsetLeft - obj.scrollLeft;
|
||||||
|
}
|
||||||
} else if (obj.x) {
|
} else if (obj.x) {
|
||||||
curleft += obj.x;
|
curleft += obj.x;
|
||||||
}
|
}
|
||||||
@ -84,9 +92,13 @@ function findPosY(obj) {
|
|||||||
var curtop = 0;
|
var curtop = 0;
|
||||||
if (obj.offsetParent) {
|
if (obj.offsetParent) {
|
||||||
while (obj.offsetParent) {
|
while (obj.offsetParent) {
|
||||||
curtop += obj.offsetTop;
|
curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop);
|
||||||
obj = obj.offsetParent;
|
obj = obj.offsetParent;
|
||||||
}
|
}
|
||||||
|
// IE offsetParent does not include the top-level
|
||||||
|
if (isIE && obj.parentElement){
|
||||||
|
curtop += obj.offsetTop - obj.scrollTop;
|
||||||
|
}
|
||||||
} else if (obj.y) {
|
} else if (obj.y) {
|
||||||
curtop += obj.y;
|
curtop += obj.y;
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,21 @@ BR-specific Form helpers
|
|||||||
from django.newforms import ValidationError
|
from django.newforms import ValidationError
|
||||||
from django.newforms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES
|
from django.newforms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_unicode
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext as _
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # For Python 2.3
|
||||||
|
|
||||||
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
|
phone_digits_re = re.compile(r'^(\d{2})[-\.]?(\d{4})[-\.]?(\d{4})$')
|
||||||
|
|
||||||
class BRZipCodeField(RegexField):
|
class BRZipCodeField(RegexField):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
|
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
|
||||||
max_length=None, min_length=None,
|
max_length=None, min_length=None,
|
||||||
error_message=ugettext('Enter a zip code in the format XXXXX-XXX.'),
|
error_message=_('Enter a zip code in the format XXXXX-XXX.'),
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
|
||||||
class BRPhoneNumberField(Field):
|
class BRPhoneNumberField(Field):
|
||||||
@ -27,7 +32,7 @@ class BRPhoneNumberField(Field):
|
|||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
||||||
raise ValidationError(ugettext('Phone numbers must be in XX-XXXX-XXXX format.'))
|
raise ValidationError(_('Phone numbers must be in XX-XXXX-XXXX format.'))
|
||||||
|
|
||||||
class BRStateSelect(Select):
|
class BRStateSelect(Select):
|
||||||
"""
|
"""
|
||||||
@ -38,6 +43,32 @@ class BRStateSelect(Select):
|
|||||||
from br_states import STATE_CHOICES
|
from br_states import STATE_CHOICES
|
||||||
super(BRStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
|
super(BRStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
|
||||||
|
|
||||||
|
class BRStateChoiceField(Field):
|
||||||
|
"""
|
||||||
|
A choice field that uses a list of Brazilian states as its choices.
|
||||||
|
"""
|
||||||
|
widget = Select
|
||||||
|
|
||||||
|
def __init__(self, required=True, widget=None, label=None,
|
||||||
|
initial=None, help_text=None):
|
||||||
|
super(BRStateChoiceField, self).__init__(required, widget, label,
|
||||||
|
initial, help_text)
|
||||||
|
from br_states import STATE_CHOICES
|
||||||
|
self.widget.choices = STATE_CHOICES
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
value = super(BRStateChoiceField, self).clean(value)
|
||||||
|
if value in EMPTY_VALUES:
|
||||||
|
value = u''
|
||||||
|
value = smart_unicode(value)
|
||||||
|
if value == u'':
|
||||||
|
return value
|
||||||
|
valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
|
||||||
|
if value not in valid_values:
|
||||||
|
raise ValidationError(_(u'Select a valid brazilian state.'
|
||||||
|
u' That state is not one'
|
||||||
|
u' of the available states.'))
|
||||||
|
return value
|
||||||
|
|
||||||
def DV_maker(v):
|
def DV_maker(v):
|
||||||
if v >= 2:
|
if v >= 2:
|
||||||
@ -69,9 +100,9 @@ class BRCPFField(CharField):
|
|||||||
try:
|
try:
|
||||||
int(value)
|
int(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError(ugettext("This field requires only numbers."))
|
raise ValidationError(_("This field requires only numbers."))
|
||||||
if len(value) != 11:
|
if len(value) != 11:
|
||||||
raise ValidationError(ugettext("This field requires at most 11 digits or 14 characters."))
|
raise ValidationError(_("This field requires at most 11 digits or 14 characters."))
|
||||||
orig_dv = value[-2:]
|
orig_dv = value[-2:]
|
||||||
|
|
||||||
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
|
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
|
||||||
@ -81,7 +112,7 @@ class BRCPFField(CharField):
|
|||||||
new_2dv = DV_maker(new_2dv % 11)
|
new_2dv = DV_maker(new_2dv % 11)
|
||||||
value = value[:-1] + str(new_2dv)
|
value = value[:-1] + str(new_2dv)
|
||||||
if value[-2:] != orig_dv:
|
if value[-2:] != orig_dv:
|
||||||
raise ValidationError(ugettext("Invalid CPF number."))
|
raise ValidationError(_("Invalid CPF number."))
|
||||||
|
|
||||||
return orig_value
|
return orig_value
|
||||||
|
|
||||||
@ -103,7 +134,7 @@ class BRCNPJField(Field):
|
|||||||
raise ValidationError("This field requires only numbers.")
|
raise ValidationError("This field requires only numbers.")
|
||||||
if len(value) != 14:
|
if len(value) != 14:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
ugettext("This field requires at least 14 digits"))
|
_("This field requires at least 14 digits"))
|
||||||
orig_dv = value[-2:]
|
orig_dv = value[-2:]
|
||||||
|
|
||||||
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
|
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
|
||||||
@ -113,7 +144,7 @@ class BRCNPJField(Field):
|
|||||||
new_2dv = DV_maker(new_2dv % 11)
|
new_2dv = DV_maker(new_2dv % 11)
|
||||||
value = value[:-1] + str(new_2dv)
|
value = value[:-1] + str(new_2dv)
|
||||||
if value[-2:] != orig_dv:
|
if value[-2:] != orig_dv:
|
||||||
raise ValidationError(ugettext("Invalid CNPJ number."))
|
raise ValidationError(_("Invalid CNPJ number."))
|
||||||
|
|
||||||
return orig_value
|
return orig_value
|
||||||
|
|
||||||
|
@ -1,15 +1,33 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.http import get_host
|
||||||
|
|
||||||
|
SITE_CACHE = {}
|
||||||
|
|
||||||
class SiteManager(models.Manager):
|
class SiteManager(models.Manager):
|
||||||
def get_current(self):
|
def get_current(self):
|
||||||
|
"""
|
||||||
|
Returns the current ``Site`` based on the SITE_ID in the
|
||||||
|
project's settings. The ``Site`` object is cached the first
|
||||||
|
time it's retrieved from the database.
|
||||||
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
try:
|
try:
|
||||||
sid = settings.SITE_ID
|
sid = settings.SITE_ID
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
raise ImproperlyConfigured("You're using the Django \"sites framework\" without having set the SITE_ID setting. Create a site in your database and set the SITE_ID setting to fix this error.")
|
raise ImproperlyConfigured("You're using the Django \"sites framework\" without having set the SITE_ID setting. Create a site in your database and set the SITE_ID setting to fix this error.")
|
||||||
return self.get(pk=sid)
|
try:
|
||||||
|
current_site = SITE_CACHE[sid]
|
||||||
|
except KeyError:
|
||||||
|
current_site = self.get(pk=sid)
|
||||||
|
SITE_CACHE[sid] = current_site
|
||||||
|
return current_site
|
||||||
|
|
||||||
|
def clear_cache(self):
|
||||||
|
"""Clears the ``Site`` object cache."""
|
||||||
|
global SITE_CACHE
|
||||||
|
SITE_CACHE = {}
|
||||||
|
|
||||||
class Site(models.Model):
|
class Site(models.Model):
|
||||||
domain = models.CharField(_('domain name'), max_length=100)
|
domain = models.CharField(_('domain name'), max_length=100)
|
||||||
@ -36,7 +54,7 @@ class RequestSite(object):
|
|||||||
The save() and delete() methods raise NotImplementedError.
|
The save() and delete() methods raise NotImplementedError.
|
||||||
"""
|
"""
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
self.domain = self.name = request.META['SERVER_NAME']
|
self.domain = self.name = get_host(request)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.domain
|
return self.domain
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
# This module is DEPRECATED!
|
|
||||||
#
|
|
||||||
# You should no longer be pointing your mod_python configuration
|
|
||||||
# at "django.core.handler".
|
|
||||||
#
|
|
||||||
# Use "django.core.handlers.modpython" instead.
|
|
||||||
|
|
||||||
from django.core.handlers.modpython import ModPythonHandler
|
|
||||||
|
|
||||||
def handler(req):
|
|
||||||
return ModPythonHandler()(req)
|
|
@ -50,6 +50,10 @@ class BaseHandler(object):
|
|||||||
|
|
||||||
def get_response(self, request):
|
def get_response(self, request):
|
||||||
"Returns an HttpResponse object for the given HttpRequest"
|
"Returns an HttpResponse object for the given HttpRequest"
|
||||||
|
response = self._real_get_response(request)
|
||||||
|
return fix_location_header(request, response)
|
||||||
|
|
||||||
|
def _real_get_response(self, request):
|
||||||
from django.core import exceptions, urlresolvers
|
from django.core import exceptions, urlresolvers
|
||||||
from django.core.mail import mail_admins
|
from django.core.mail import mail_admins
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -129,3 +133,16 @@ class BaseHandler(object):
|
|||||||
"Helper function to return the traceback as a string"
|
"Helper function to return the traceback as a string"
|
||||||
import traceback
|
import traceback
|
||||||
return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
|
return '\n'.join(traceback.format_exception(*(exc_info or sys.exc_info())))
|
||||||
|
|
||||||
|
def fix_location_header(request, response):
|
||||||
|
"""
|
||||||
|
Ensure that we always use an absolute URI in any location header in the
|
||||||
|
response. This is required by RFC 2616, section 14.30.
|
||||||
|
|
||||||
|
Code constructing response objects is free to insert relative paths and
|
||||||
|
this function converts them to absolute paths.
|
||||||
|
"""
|
||||||
|
if 'Location' in response.headers and http.get_host(request):
|
||||||
|
response['Location'] = request.build_absolute_uri(response['Location'])
|
||||||
|
return response
|
||||||
|
|
||||||
|
@ -181,10 +181,15 @@ def isValidImage(field_data, all_data):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
|
raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
|
||||||
try:
|
try:
|
||||||
Image.open(StringIO(content))
|
# load() is the only method that can spot a truncated JPEG,
|
||||||
except (IOError, OverflowError): # Python Imaging Library doesn't recognize it as an image
|
# but it cannot be called sanely after verify()
|
||||||
# OverflowError is due to a bug in PIL with Python 2.4+ which can cause
|
trial_image = Image.open(StringIO(content))
|
||||||
# it to gag on OLE files.
|
trial_image.load()
|
||||||
|
# verify() is the only method that can spot a corrupt PNG,
|
||||||
|
# but it must be called immediately after the constructor
|
||||||
|
trial_image = Image.open(StringIO(content))
|
||||||
|
trial_image.verify()
|
||||||
|
except Exception: # Python Imaging Library doesn't recognize it as an image
|
||||||
raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
|
raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.")
|
||||||
|
|
||||||
def isValidImageURL(field_data, all_data):
|
def isValidImageURL(field_data, all_data):
|
||||||
|
@ -241,10 +241,12 @@ class Model(object):
|
|||||||
placeholders = ['%s'] * len(field_names)
|
placeholders = ['%s'] * len(field_names)
|
||||||
if self._meta.order_with_respect_to:
|
if self._meta.order_with_respect_to:
|
||||||
field_names.append(qn('_order'))
|
field_names.append(qn('_order'))
|
||||||
# TODO: This assumes the database supports subqueries.
|
placeholders.append('%s')
|
||||||
placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
|
subsel = 'SELECT COUNT(*) FROM %s WHERE %s = %%s' % (
|
||||||
(qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column)))
|
qn(self._meta.db_table),
|
||||||
db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
|
qn(self._meta.order_with_respect_to.column))
|
||||||
|
cursor.execute(subsel, (getattr(self, self._meta.order_with_respect_to.attname),))
|
||||||
|
db_values.append(cursor.fetchone()[0])
|
||||||
if db_values:
|
if db_values:
|
||||||
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
|
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
|
||||||
(qn(self._meta.db_table), ','.join(field_names),
|
(qn(self._meta.db_table), ','.join(field_names),
|
||||||
|
@ -2,6 +2,7 @@ import os
|
|||||||
from Cookie import SimpleCookie
|
from Cookie import SimpleCookie
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
|
from urlparse import urljoin
|
||||||
from django.utils.datastructures import MultiValueDict, FileDict
|
from django.utils.datastructures import MultiValueDict, FileDict
|
||||||
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
|
||||||
|
|
||||||
@ -42,10 +43,24 @@ class HttpRequest(object):
|
|||||||
return key in self.GET or key in self.POST
|
return key in self.GET or key in self.POST
|
||||||
|
|
||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def get_full_path(self):
|
def get_full_path(self):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def build_absolute_uri(self, location=None):
|
||||||
|
"""
|
||||||
|
Builds an absolute URI from the location and the variables available in
|
||||||
|
this request. If no location is specified, the absolute URI is built on
|
||||||
|
``request.get_full_path()``.
|
||||||
|
"""
|
||||||
|
if not location:
|
||||||
|
location = self.get_full_path()
|
||||||
|
if not ':' in location:
|
||||||
|
current_uri = '%s://%s%s' % (self.is_secure() and 'https' or 'http',
|
||||||
|
get_host(self), self.path)
|
||||||
|
location = urljoin(current_uri, location)
|
||||||
|
return location
|
||||||
|
|
||||||
def is_secure(self):
|
def is_secure(self):
|
||||||
return os.environ.get("HTTPS") == "on"
|
return os.environ.get("HTTPS") == "on"
|
||||||
|
|
||||||
@ -364,9 +379,16 @@ class HttpResponseServerError(HttpResponse):
|
|||||||
|
|
||||||
def get_host(request):
|
def get_host(request):
|
||||||
"Gets the HTTP host from the environment or request headers."
|
"Gets the HTTP host from the environment or request headers."
|
||||||
|
# We try three options, in order of decreasing preference.
|
||||||
host = request.META.get('HTTP_X_FORWARDED_HOST', '')
|
host = request.META.get('HTTP_X_FORWARDED_HOST', '')
|
||||||
if not host:
|
if 'HTTP_HOST' in request.META:
|
||||||
host = request.META.get('HTTP_HOST', '')
|
host = request.META['HTTP_HOST']
|
||||||
|
else:
|
||||||
|
# Reconstruct the host using the algorithm from PEP 333.
|
||||||
|
host = request.META['SERVER_NAME']
|
||||||
|
server_port = request.META['SERVER_PORT']
|
||||||
|
if server_port != (request.is_secure() and 443 or 80):
|
||||||
|
host = '%s:%s' % (host, server_port)
|
||||||
return host
|
return host
|
||||||
|
|
||||||
# It's neither necessary nor appropriate to use
|
# It's neither necessary nor appropriate to use
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
Field classes
|
Field classes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
@ -100,6 +101,12 @@ class Field(object):
|
|||||||
"""
|
"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
result = copy.copy(self)
|
||||||
|
memo[id(self)] = result
|
||||||
|
result.widget = copy.deepcopy(self.widget, memo)
|
||||||
|
return result
|
||||||
|
|
||||||
class CharField(Field):
|
class CharField(Field):
|
||||||
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
|
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
|
||||||
self.max_length, self.min_length = max_length, min_length
|
self.max_length, self.min_length = max_length, min_length
|
||||||
@ -386,10 +393,15 @@ class ImageField(FileField):
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
try:
|
try:
|
||||||
Image.open(StringIO(f.content))
|
# load() is the only method that can spot a truncated JPEG,
|
||||||
except (IOError, OverflowError): # Python Imaging Library doesn't recognize it as an image
|
# but it cannot be called sanely after verify()
|
||||||
# OverflowError is due to a bug in PIL with Python 2.4+ which can cause
|
trial_image = Image.open(StringIO(f.content))
|
||||||
# it to gag on OLE files.
|
trial_image.load()
|
||||||
|
# verify() is the only method that can spot a corrupt PNG,
|
||||||
|
# but it must be called immediately after the constructor
|
||||||
|
trial_image = Image.open(StringIO(f.content))
|
||||||
|
trial_image.verify()
|
||||||
|
except Exception: # Python Imaging Library doesn't recognize it as an image
|
||||||
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
|
||||||
|
|
||||||
@ -409,6 +421,9 @@ class URLField(RegexField):
|
|||||||
self.user_agent = validator_user_agent
|
self.user_agent = validator_user_agent
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
|
# If no URL scheme given, assume http://
|
||||||
|
if value and '://' not in value:
|
||||||
|
value = u'http://%s' % value
|
||||||
value = super(URLField, self).clean(value)
|
value = super(URLField, self).clean(value)
|
||||||
if value == u'':
|
if value == u'':
|
||||||
return value
|
return value
|
||||||
|
@ -31,7 +31,7 @@ class SortedDictFromList(SortedDict):
|
|||||||
dict.__init__(self, dict(data))
|
dict.__init__(self, dict(data))
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return SortedDictFromList([(k, copy.copy(v)) for k, v in self.items()])
|
return SortedDictFromList([(k, copy.deepcopy(v)) for k, v in self.items()])
|
||||||
|
|
||||||
class DeclarativeFieldsMetaclass(type):
|
class DeclarativeFieldsMetaclass(type):
|
||||||
"""
|
"""
|
||||||
|
@ -84,12 +84,8 @@ class TestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.status_code, status_code,
|
self.assertEqual(response.status_code, status_code,
|
||||||
("Response didn't redirect as expected: Response code was %d"
|
("Response didn't redirect as expected: Response code was %d"
|
||||||
" (expected %d)" % (response.status_code, status_code)))
|
" (expected %d)" % (response.status_code, status_code)))
|
||||||
scheme, netloc, path, query, fragment = urlsplit(response['Location'])
|
url = response['Location']
|
||||||
url = path
|
scheme, netloc, path, query, fragment = urlsplit(url)
|
||||||
if query:
|
|
||||||
url += '?' + query
|
|
||||||
if fragment:
|
|
||||||
url += '#' + fragment
|
|
||||||
self.assertEqual(url, expected_url,
|
self.assertEqual(url, expected_url,
|
||||||
"Response redirected to '%s', expected '%s'" % (url, expected_url))
|
"Response redirected to '%s', expected '%s'" % (url, expected_url))
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ from django.http import Http404, HttpResponse
|
|||||||
def archive_index(request, queryset, date_field, num_latest=15,
|
def archive_index(request, queryset, date_field, num_latest=15,
|
||||||
template_name=None, template_loader=loader,
|
template_name=None, template_loader=loader,
|
||||||
extra_context=None, allow_empty=False, context_processors=None,
|
extra_context=None, allow_empty=False, context_processors=None,
|
||||||
mimetype=None, allow_future=False):
|
mimetype=None, allow_future=False, template_object_name='latest'):
|
||||||
"""
|
"""
|
||||||
Generic top-level archive of date-based objects.
|
Generic top-level archive of date-based objects.
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ def archive_index(request, queryset, date_field, num_latest=15,
|
|||||||
t = template_loader.get_template(template_name)
|
t = template_loader.get_template(template_name)
|
||||||
c = RequestContext(request, {
|
c = RequestContext(request, {
|
||||||
'date_list' : date_list,
|
'date_list' : date_list,
|
||||||
'latest' : latest,
|
template_object_name : latest,
|
||||||
}, context_processors)
|
}, context_processors)
|
||||||
for key, value in extra_context.items():
|
for key, value in extra_context.items():
|
||||||
if callable(value):
|
if callable(value):
|
||||||
|
@ -9,20 +9,26 @@ def set_language(request):
|
|||||||
"""
|
"""
|
||||||
Redirect to a given url while setting the chosen language in the
|
Redirect to a given url while setting the chosen language in the
|
||||||
session or cookie. The url and the language code need to be
|
session or cookie. The url and the language code need to be
|
||||||
specified in the GET parameters.
|
specified in the request parameters.
|
||||||
|
|
||||||
|
Since this view changes how the user will see the rest of the site, it must
|
||||||
|
only be accessed as a POST request. If called as a GET request, it will
|
||||||
|
redirect to the page in the request (the 'next' parameter) without changing
|
||||||
|
any state.
|
||||||
"""
|
"""
|
||||||
lang_code = request.GET.get('language', None)
|
|
||||||
next = request.GET.get('next', None)
|
next = request.GET.get('next', None)
|
||||||
if not next:
|
if not next:
|
||||||
next = request.META.get('HTTP_REFERER', None)
|
next = request.META.get('HTTP_REFERER', None)
|
||||||
if not next:
|
if not next:
|
||||||
next = '/'
|
next = '/'
|
||||||
response = http.HttpResponseRedirect(next)
|
response = http.HttpResponseRedirect(next)
|
||||||
if lang_code and check_for_language(lang_code):
|
if request.method == 'POST':
|
||||||
if hasattr(request, 'session'):
|
lang_code = request.POST.get('language', None)
|
||||||
request.session['django_language'] = lang_code
|
if lang_code and check_for_language(lang_code):
|
||||||
else:
|
if hasattr(request, 'session'):
|
||||||
response.set_cookie('django_language', lang_code)
|
request.session['django_language'] = lang_code
|
||||||
|
else:
|
||||||
|
response.set_cookie('django_language', lang_code)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
NullSource = """
|
NullSource = """
|
||||||
|
@ -799,6 +799,9 @@ of the arguments is required, but you should use at least one of them.
|
|||||||
|
|
||||||
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
|
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
|
||||||
|
|
||||||
|
The combined number of placeholders in the list of strings for ``select``
|
||||||
|
or ``where`` should equal the number of values in the ``params`` list.
|
||||||
|
|
||||||
QuerySet methods that do not return QuerySets
|
QuerySet methods that do not return QuerySets
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
@ -201,6 +201,10 @@ a date in the *future* are not included unless you set ``allow_future`` to
|
|||||||
specified in ``date_field`` is greater than the current date/time. By
|
specified in ``date_field`` is greater than the current date/time. By
|
||||||
default, this is ``False``.
|
default, this is ``False``.
|
||||||
|
|
||||||
|
* **New in Django development version:** ``template_object_name``:
|
||||||
|
Designates the name of the template variable to use in the template
|
||||||
|
context. By default, this is ``'latest'``.
|
||||||
|
|
||||||
**Template name:**
|
**Template name:**
|
||||||
|
|
||||||
If ``template_name`` isn't specified, this view will use the template
|
If ``template_name`` isn't specified, this view will use the template
|
||||||
@ -221,10 +225,16 @@ In addition to ``extra_context``, the template's context will be:
|
|||||||
years that have objects available according to ``queryset``. These are
|
years that have objects available according to ``queryset``. These are
|
||||||
ordered in reverse. This is equivalent to
|
ordered in reverse. This is equivalent to
|
||||||
``queryset.dates(date_field, 'year')[::-1]``.
|
``queryset.dates(date_field, 'year')[::-1]``.
|
||||||
|
|
||||||
* ``latest``: The ``num_latest`` objects in the system, ordered descending
|
* ``latest``: The ``num_latest`` objects in the system, ordered descending
|
||||||
by ``date_field``. For example, if ``num_latest`` is ``10``, then
|
by ``date_field``. For example, if ``num_latest`` is ``10``, then
|
||||||
``latest`` will be a list of the latest 10 objects in ``queryset``.
|
``latest`` will be a list of the latest 10 objects in ``queryset``.
|
||||||
|
|
||||||
|
**New in Django development version:** This variable's name depends on
|
||||||
|
the ``template_object_name`` parameter, which is ``'latest'`` by default.
|
||||||
|
If ``template_object_name`` is ``'foo'``, this variable's name will be
|
||||||
|
``foo``.
|
||||||
|
|
||||||
.. _RequestContext docs: ../templates_python/#subclassing-context-requestcontext
|
.. _RequestContext docs: ../templates_python/#subclassing-context-requestcontext
|
||||||
|
|
||||||
``django.views.generic.date_based.archive_year``
|
``django.views.generic.date_based.archive_year``
|
||||||
@ -764,8 +774,8 @@ 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
|
* **New in Django development version:** ``page_range``: A list of the
|
||||||
is 1-based.
|
page numbers that are available. This is 1-based.
|
||||||
|
|
||||||
Notes on pagination
|
Notes on pagination
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
@ -788,7 +798,11 @@ specify the page number in the URL in one of two ways:
|
|||||||
to create a link to every page of results.
|
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
|
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
|
represented as page ``1``.
|
||||||
|
|
||||||
|
**New in Django development version:**
|
||||||
|
|
||||||
|
As a special case, you are also permitted to use
|
||||||
``last`` as a value for ``page``::
|
``last`` as a value for ``page``::
|
||||||
|
|
||||||
/objects/?page=last
|
/objects/?page=last
|
||||||
|
@ -127,16 +127,24 @@ Installing an official release
|
|||||||
|
|
||||||
1. Download the latest release from our `download page`_.
|
1. Download the latest release from our `download page`_.
|
||||||
|
|
||||||
2. Untar the downloaded file (e.g. ``tar xzvf Django-NNN.tar.gz``).
|
2. Untar the downloaded file (e.g. ``tar xzvf Django-NNN.tar.gz``,
|
||||||
|
where ``NNN`` is the version number of the latest release).
|
||||||
|
If you're using Windows, you can download the command-line tool
|
||||||
|
bsdtar_ to do this, or you can use a GUI-based tool such as 7-zip_.
|
||||||
|
|
||||||
3. Change into the downloaded directory (e.g. ``cd Django-NNN``).
|
3. Change into the directory created in step 2 (e.g. ``cd Django-NNN``).
|
||||||
|
|
||||||
4. Run ``sudo python setup.py install``.
|
4. If you're using Linux, Mac OS X or some other flavor of Unix, enter
|
||||||
|
the command ``sudo python setup.py install`` at the shell prompt.
|
||||||
|
If you're using Windows, start up a command shell with administrator
|
||||||
|
privileges and run the command ``setup.py install``.
|
||||||
|
|
||||||
The command will install Django in your Python installation's ``site-packages``
|
These commands will install Django in your Python installation's
|
||||||
directory.
|
``site-packages`` directory.
|
||||||
|
|
||||||
.. _distribution specific notes: ../distributions/
|
.. _distribution specific notes: ../distributions/
|
||||||
|
.. _bsdtar: http://gnuwin32.sourceforge.net/packages/bsdtar.htm
|
||||||
|
.. _7-zip: http://www.7-zip.org/
|
||||||
|
|
||||||
Installing the development version
|
Installing the development version
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -144,34 +152,55 @@ Installing the development version
|
|||||||
If you'd like to be able to update your Django code occasionally with the
|
If you'd like to be able to update your Django code occasionally with the
|
||||||
latest bug fixes and improvements, follow these instructions:
|
latest bug fixes and improvements, follow these instructions:
|
||||||
|
|
||||||
1. Make sure you have Subversion_ installed.
|
1. Make sure that you have Subversion_ installed, and that you can run its
|
||||||
2. Check out the Django code into your Python ``site-packages`` directory.
|
commands from a shell. (Enter ``svn help`` at a shell prompt to test
|
||||||
|
this.)
|
||||||
|
|
||||||
On Linux / Mac OSX / Unix, do this::
|
2. Check out Django's main development branch (the 'trunk') like so::
|
||||||
|
|
||||||
svn co http://code.djangoproject.com/svn/django/trunk/ django_src
|
svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
|
||||||
ln -s `pwd`/django_src/django SITE-PACKAGES-DIR/django
|
|
||||||
|
3. Next, make sure that the Python interpreter can load Django's code. There
|
||||||
|
are various ways of accomplishing this. One of the most convenient, on
|
||||||
|
Linux, Mac OSX or other Unix-like systems, is to use a symbolic link::
|
||||||
|
|
||||||
|
ln -s `pwd`/django-trunk/django SITE-PACKAGES-DIR/django
|
||||||
|
|
||||||
(In the above line, change ``SITE-PACKAGES-DIR`` to match the location of
|
(In the above line, change ``SITE-PACKAGES-DIR`` to match the location of
|
||||||
your system's ``site-packages`` directory, as explained in the
|
your system's ``site-packages`` directory, as explained in the
|
||||||
"Where are my ``site-packages`` stored?" section above.)
|
"Where are my ``site-packages`` stored?" section above.)
|
||||||
|
|
||||||
On Windows, do this::
|
Alternatively, you can define your ``PYTHONPATH`` environment variable
|
||||||
|
so that it includes the ``django`` subdirectory of ``django-trunk``.
|
||||||
|
This is perhaps the most convenient solution on Windows systems, which
|
||||||
|
don't support symbolic links. (Environment variables can be defined on
|
||||||
|
Windows systems `from the Control Panel`_.)
|
||||||
|
|
||||||
svn co http://code.djangoproject.com/svn/django/trunk/django c:\Python24\lib\site-packages\django
|
.. admonition:: What about Apache and mod_python?
|
||||||
|
|
||||||
3. Copy the file ``django_src/django/bin/django-admin.py`` to somewhere on your
|
If you take the approach of setting ``PYTHONPATH``, you'll need to
|
||||||
system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
|
remember to do the same thing in your Apache configuration once you
|
||||||
|
deploy your production site. Do this by setting ``PythonPath`` in your
|
||||||
|
Apache configuration file.
|
||||||
|
|
||||||
|
More information about deployment is available, of course, in our
|
||||||
|
`How to use Django with mod_python`_ documentation.
|
||||||
|
|
||||||
|
.. _How to use Django with mod_python: ../modpython/
|
||||||
|
|
||||||
|
4. Copy the file ``django-trunk/django/bin/django-admin.py`` to somewhere on
|
||||||
|
your system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
|
||||||
(Windows). This step simply lets you type ``django-admin.py`` from within
|
(Windows). This step simply lets you type ``django-admin.py`` from within
|
||||||
any directory, rather than having to qualify the command with the full path
|
any directory, rather than having to qualify the command with the full path
|
||||||
to the file.
|
to the file.
|
||||||
|
|
||||||
You *don't* have to run ``python setup.py install``, because that command
|
You *don't* have to run ``python setup.py install``, because you've already
|
||||||
takes care of steps 2 and 3 for you.
|
carried out the equivalent actions in steps 3 and 4.
|
||||||
|
|
||||||
When you want to update your copy of the Django source code, just run the
|
When you want to update your copy of the Django source code, just run the
|
||||||
command ``svn update`` from within the ``django`` directory. When you do this,
|
command ``svn update`` from within the ``django-trunk`` directory. When you do
|
||||||
Subversion will automatically download any changes.
|
this, Subversion will automatically download any changes.
|
||||||
|
|
||||||
.. _`download page`: http://www.djangoproject.com/download/
|
.. _`download page`: http://www.djangoproject.com/download/
|
||||||
.. _Subversion: http://subversion.tigris.org/
|
.. _Subversion: http://subversion.tigris.org/
|
||||||
|
.. _from the Control Panel: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/sysdm_advancd_environmnt_addchange_variable.mspx
|
||||||
|
@ -1550,8 +1550,8 @@ Finally, note that in order to use ``list_display_links``, you must define
|
|||||||
|
|
||||||
Set ``list_filter`` to activate filters in the right sidebar of the change list
|
Set ``list_filter`` to activate filters in the right sidebar of the change list
|
||||||
page of the admin. This should be a list of field names, and each specified
|
page of the admin. This should be a list of field names, and each specified
|
||||||
field should be either a ``BooleanField``, ``DateField``, ``DateTimeField``
|
field should be either a ``BooleanField``, ``CharField``, ``DateField``,
|
||||||
or ``ForeignKey``.
|
``DateTimeField``, ``IntegerField`` or ``ForeignKey``.
|
||||||
|
|
||||||
This example, taken from the ``django.contrib.auth.models.User`` model, shows
|
This example, taken from the ``django.contrib.auth.models.User`` model, shows
|
||||||
how both ``list_display`` and ``list_filter`` work::
|
how both ``list_display`` and ``list_filter`` work::
|
||||||
|
@ -83,7 +83,7 @@ need to write your ``PythonPath`` directive as::
|
|||||||
With this path, ``import weblog`` and ``import mysite.settings`` will both
|
With this path, ``import weblog`` and ``import mysite.settings`` will both
|
||||||
work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
|
work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
|
||||||
lived under the ``weblog/`` directory, you would *also* need to add
|
lived under the ``weblog/`` directory, you would *also* need to add
|
||||||
``/var/production/django-apps/weblog/`` to your ``PythonPath``. Remember: the
|
``/usr/local/django-apps/weblog/`` to your ``PythonPath``. Remember: the
|
||||||
**parent directories** of anything you import directly must be on the Python
|
**parent directories** of anything you import directly must be on the Python
|
||||||
path.
|
path.
|
||||||
|
|
||||||
|
@ -161,6 +161,18 @@ Methods
|
|||||||
|
|
||||||
Example: ``"/music/bands/the_beatles/?print=true"``
|
Example: ``"/music/bands/the_beatles/?print=true"``
|
||||||
|
|
||||||
|
``build_absolute_uri(location)``
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
Returns the absolute URI form of ``location``. If no location is provided,
|
||||||
|
the location will be set to ``request.get_full_path()``.
|
||||||
|
|
||||||
|
If the location is already an absolute URI, it will not be altered.
|
||||||
|
Otherwise the absolute URI is built using the server variables available in
|
||||||
|
this request.
|
||||||
|
|
||||||
|
Example: ``"http://example.com/music/bands/the_beatles/?print=true"``
|
||||||
|
|
||||||
``is_secure()``
|
``is_secure()``
|
||||||
Returns ``True`` if the request is secure; that is, if it was made with
|
Returns ``True`` if the request is secure; that is, if it was made with
|
||||||
HTTPS.
|
HTTPS.
|
||||||
@ -184,8 +196,8 @@ 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
|
Raises ``django.utils.datastructure.MultiValueDictKeyError`` if the key
|
||||||
does not exist (fortunately, this is a subclass of Python's standard
|
does not exist. (This is a subclass of Python's standard ``KeyError``,
|
||||||
``KeyError``, so you can stick to catching ``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
|
||||||
|
@ -213,6 +213,31 @@ To do this, you can use the sites framework. A simple example::
|
|||||||
>>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
|
>>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
|
||||||
'http://example.com/mymodel/objects/3/'
|
'http://example.com/mymodel/objects/3/'
|
||||||
|
|
||||||
|
Caching the current ``Site`` object
|
||||||
|
===================================
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
As the current site is stored in the database, each call to
|
||||||
|
``Site.objects.get_current()`` could result in a database query. But Django is a
|
||||||
|
little cleverer than that: on the first request, the current site is cached, and
|
||||||
|
any subsequent call returns the cached data instead of hitting the database.
|
||||||
|
|
||||||
|
If for any reason you want to force a database query, you can tell Django to
|
||||||
|
clear the cache using ``Site.objects.clear_cache()``::
|
||||||
|
|
||||||
|
# First call; current site fetched from database.
|
||||||
|
current_site = Site.objects.get_current()
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# Second call; current site fetched from cache.
|
||||||
|
current_site = Site.objects.get_current()
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# Force a database query for the third call.
|
||||||
|
Site.objects.clear_cache()
|
||||||
|
current_site = Site.objects.get_current()
|
||||||
|
|
||||||
The ``CurrentSiteManager``
|
The ``CurrentSiteManager``
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
@ -1431,4 +1431,4 @@ Read the document `The Django template language: For Python programmers`_ if
|
|||||||
you're interested in learning the template system from a technical
|
you're interested in learning the template system from a technical
|
||||||
perspective -- how it works and how to extend it.
|
perspective -- how it works and how to extend it.
|
||||||
|
|
||||||
.. _The Django template language: For Python programmers: ../templates_python/
|
.. _The Django template language\: For Python programmers: ../templates_python/
|
||||||
|
@ -642,12 +642,12 @@ your function. Example::
|
|||||||
"Converts a string into all lowercase"
|
"Converts a string into all lowercase"
|
||||||
return value.lower()
|
return value.lower()
|
||||||
|
|
||||||
Template filters which expect strings
|
Template filters that expect strings
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
If you're writing a template filter which only expects a string as the first
|
If you're writing a template filter that only expects a string as the first
|
||||||
argument, you should use the included decorator ``stringfilter``. This will
|
argument, you should use the decorator ``stringfilter``. This will
|
||||||
convert an object to it's string value before being passed to your function::
|
convert an object to its string value before being passed to your function::
|
||||||
|
|
||||||
from django.template.defaultfilters import stringfilter
|
from django.template.defaultfilters import stringfilter
|
||||||
|
|
||||||
@ -655,6 +655,10 @@ convert an object to it's string value before being passed to your function::
|
|||||||
def lower(value):
|
def lower(value):
|
||||||
return value.lower()
|
return value.lower()
|
||||||
|
|
||||||
|
This way, you'll be able to pass, say, an integer to this filter, and it
|
||||||
|
won't cause an ``AttributeError`` (because integers don't have ``lower()``
|
||||||
|
methods).
|
||||||
|
|
||||||
Registering a custom filters
|
Registering a custom filters
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -83,23 +83,31 @@ class ClientTest(TestCase):
|
|||||||
def test_redirect(self):
|
def test_redirect(self):
|
||||||
"GET a URL that redirects elsewhere"
|
"GET a URL that redirects elsewhere"
|
||||||
response = self.client.get('/test_client/redirect_view/')
|
response = self.client.get('/test_client/redirect_view/')
|
||||||
|
|
||||||
# Check that the response was a 302 (redirect)
|
# Check that the response was a 302 (redirect)
|
||||||
self.assertRedirects(response, '/test_client/get_view/')
|
self.assertRedirects(response, 'http://testserver/test_client/get_view/')
|
||||||
|
|
||||||
|
client_providing_host = Client(HTTP_HOST='django.testserver')
|
||||||
|
response = client_providing_host.get('/test_client/redirect_view/')
|
||||||
|
# Check that the response was a 302 (redirect) with absolute URI
|
||||||
|
self.assertRedirects(response, 'http://django.testserver/test_client/get_view/')
|
||||||
|
|
||||||
def test_redirect_with_query(self):
|
def test_redirect_with_query(self):
|
||||||
"GET a URL that redirects with given GET parameters"
|
"GET a URL that redirects with given GET parameters"
|
||||||
response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
|
response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
|
||||||
|
|
||||||
# Check if parameters are intact
|
# Check if parameters are intact
|
||||||
self.assertRedirects(response, '/test_client/get_view/?var=value')
|
self.assertRedirects(response, 'http://testserver/test_client/get_view/?var=value')
|
||||||
|
|
||||||
def test_permanent_redirect(self):
|
def test_permanent_redirect(self):
|
||||||
"GET a URL that redirects permanently elsewhere"
|
"GET a URL that redirects permanently elsewhere"
|
||||||
response = self.client.get('/test_client/permanent_redirect_view/')
|
response = self.client.get('/test_client/permanent_redirect_view/')
|
||||||
|
|
||||||
# Check that the response was a 301 (permanent redirect)
|
# Check that the response was a 301 (permanent redirect)
|
||||||
self.assertRedirects(response, '/test_client/get_view/', status_code=301)
|
self.assertRedirects(response, 'http://testserver/test_client/get_view/', status_code=301)
|
||||||
|
|
||||||
|
client_providing_host = Client(HTTP_HOST='django.testserver')
|
||||||
|
response = client_providing_host.get('/test_client/permanent_redirect_view/')
|
||||||
|
# Check that the response was a 301 (permanent redirect) with absolute URI
|
||||||
|
self.assertRedirects(response, 'http://django.testserver/test_client/get_view/', status_code=301)
|
||||||
|
|
||||||
def test_redirect_to_strange_location(self):
|
def test_redirect_to_strange_location(self):
|
||||||
"GET a URL that redirects to a non-200 page"
|
"GET a URL that redirects to a non-200 page"
|
||||||
@ -107,7 +115,7 @@ class ClientTest(TestCase):
|
|||||||
|
|
||||||
# Check that the response was a 302, and that
|
# Check that the response was a 302, and that
|
||||||
# the attempt to get the redirection location returned 301 when retrieved
|
# the attempt to get the redirection location returned 301 when retrieved
|
||||||
self.assertRedirects(response, '/test_client/permanent_redirect_view/', target_status_code=301)
|
self.assertRedirects(response, 'http://testserver/test_client/permanent_redirect_view/', target_status_code=301)
|
||||||
|
|
||||||
def test_notfound_response(self):
|
def test_notfound_response(self):
|
||||||
"GET a URL that responds as '404:Not Found'"
|
"GET a URL that responds as '404:Not Found'"
|
||||||
@ -231,11 +239,11 @@ class ClientTest(TestCase):
|
|||||||
|
|
||||||
# Get the page without logging in. Should result in 302.
|
# Get the page without logging in. Should result in 302.
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
response = self.client.get('/test_client/login_protected_view/')
|
||||||
self.assertRedirects(response, '/accounts/login/?next=/test_client/login_protected_view/')
|
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
|
||||||
|
|
||||||
# Log in
|
# Log in
|
||||||
login = self.client.login(username='testclient', password='password')
|
login = self.client.login(username='testclient', password='password')
|
||||||
self.assertTrue(login, 'Could not log in')
|
self.failUnless(login, 'Could not log in')
|
||||||
|
|
||||||
# Request a page that requires a login
|
# Request a page that requires a login
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
response = self.client.get('/test_client/login_protected_view/')
|
||||||
@ -269,7 +277,7 @@ class ClientTest(TestCase):
|
|||||||
|
|
||||||
# Request a page that requires a login
|
# Request a page that requires a login
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
response = self.client.get('/test_client/login_protected_view/')
|
||||||
self.assertRedirects(response, '/accounts/login/?next=/test_client/login_protected_view/')
|
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/login_protected_view/')
|
||||||
|
|
||||||
def test_session_modifying_view(self):
|
def test_session_modifying_view(self):
|
||||||
"Request a page that modifies the session"
|
"Request a page that modifies the session"
|
||||||
|
@ -980,6 +980,20 @@ u'41-3562-3464'
|
|||||||
>>> w.render('states', 'PR')
|
>>> w.render('states', 'PR')
|
||||||
u'<select name="states">\n<option value="AC">Acre</option>\n<option value="AL">Alagoas</option>\n<option value="AP">Amap\xe1</option>\n<option value="AM">Amazonas</option>\n<option value="BA">Bahia</option>\n<option value="CE">Cear\xe1</option>\n<option value="DF">Distrito Federal</option>\n<option value="ES">Esp\xedrito Santo</option>\n<option value="GO">Goi\xe1s</option>\n<option value="MA">Maranh\xe3o</option>\n<option value="MT">Mato Grosso</option>\n<option value="MS">Mato Grosso do Sul</option>\n<option value="MG">Minas Gerais</option>\n<option value="PA">Par\xe1</option>\n<option value="PB">Para\xedba</option>\n<option value="PR" selected="selected">Paran\xe1</option>\n<option value="PE">Pernambuco</option>\n<option value="PI">Piau\xed</option>\n<option value="RJ">Rio de Janeiro</option>\n<option value="RN">Rio Grande do Norte</option>\n<option value="RS">Rio Grande do Sul</option>\n<option value="RO">Rond\xf4nia</option>\n<option value="RR">Roraima</option>\n<option value="SC">Santa Catarina</option>\n<option value="SP">S\xe3o Paulo</option>\n<option value="SE">Sergipe</option>\n<option value="TO">Tocantins</option>\n</select>'
|
u'<select name="states">\n<option value="AC">Acre</option>\n<option value="AL">Alagoas</option>\n<option value="AP">Amap\xe1</option>\n<option value="AM">Amazonas</option>\n<option value="BA">Bahia</option>\n<option value="CE">Cear\xe1</option>\n<option value="DF">Distrito Federal</option>\n<option value="ES">Esp\xedrito Santo</option>\n<option value="GO">Goi\xe1s</option>\n<option value="MA">Maranh\xe3o</option>\n<option value="MT">Mato Grosso</option>\n<option value="MS">Mato Grosso do Sul</option>\n<option value="MG">Minas Gerais</option>\n<option value="PA">Par\xe1</option>\n<option value="PB">Para\xedba</option>\n<option value="PR" selected="selected">Paran\xe1</option>\n<option value="PE">Pernambuco</option>\n<option value="PI">Piau\xed</option>\n<option value="RJ">Rio de Janeiro</option>\n<option value="RN">Rio Grande do Norte</option>\n<option value="RS">Rio Grande do Sul</option>\n<option value="RO">Rond\xf4nia</option>\n<option value="RR">Roraima</option>\n<option value="SC">Santa Catarina</option>\n<option value="SP">S\xe3o Paulo</option>\n<option value="SE">Sergipe</option>\n<option value="TO">Tocantins</option>\n</select>'
|
||||||
|
|
||||||
|
# BRStateChoiceField #########################################################
|
||||||
|
>>> from django.contrib.localflavor.br.forms import BRStateChoiceField
|
||||||
|
>>> f = BRStateChoiceField()
|
||||||
|
>>> ', '.join([f.clean(s) for s, _ in f.widget.choices])
|
||||||
|
u'AC, AL, AP, AM, BA, CE, DF, ES, GO, MA, MT, MS, MG, PA, PB, PR, PE, PI, RJ, RN, RS, RO, RR, SC, SP, SE, TO'
|
||||||
|
>>> f.clean('')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'This field is required.']
|
||||||
|
>>> f.clean('pr')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid brazilian state. That state is not one of the available states.']
|
||||||
|
|
||||||
# DEZipCodeField ##############################################################
|
# DEZipCodeField ##############################################################
|
||||||
|
|
||||||
>>> from django.contrib.localflavor.de.forms import DEZipCodeField
|
>>> from django.contrib.localflavor.de.forms import DEZipCodeField
|
||||||
|
@ -1623,10 +1623,6 @@ u'http://200.8.9.10:8000/test'
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'Enter a valid URL.']
|
ValidationError: [u'Enter a valid URL.']
|
||||||
>>> f.clean('example.com')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValidationError: [u'Enter a valid URL.']
|
|
||||||
>>> f.clean('http://')
|
>>> f.clean('http://')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
@ -1657,10 +1653,6 @@ u'http://www.example.com'
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValidationError: [u'Enter a valid URL.']
|
ValidationError: [u'Enter a valid URL.']
|
||||||
>>> f.clean('example.com')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValidationError: [u'Enter a valid URL.']
|
|
||||||
>>> f.clean('http://')
|
>>> f.clean('http://')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
@ -1714,6 +1706,15 @@ Traceback (most recent call last):
|
|||||||
...
|
...
|
||||||
ValidationError: [u'Ensure this value has at most 20 characters (it has 37).']
|
ValidationError: [u'Ensure this value has at most 20 characters (it has 37).']
|
||||||
|
|
||||||
|
URLField should prepend 'http://' if no scheme was given
|
||||||
|
>>> f = URLField(required=False)
|
||||||
|
>>> f.clean('example.com')
|
||||||
|
u'http://example.com'
|
||||||
|
>>> f.clean('')
|
||||||
|
u''
|
||||||
|
>>> f.clean('https://example.com')
|
||||||
|
u'https://example.com'
|
||||||
|
|
||||||
# BooleanField ################################################################
|
# BooleanField ################################################################
|
||||||
|
|
||||||
>>> f = BooleanField()
|
>>> f = BooleanField()
|
||||||
@ -2690,16 +2691,24 @@ to the next.
|
|||||||
... super(Person, self).__init__(*args, **kwargs)
|
... super(Person, self).__init__(*args, **kwargs)
|
||||||
... if names_required:
|
... if names_required:
|
||||||
... self.fields['first_name'].required = True
|
... self.fields['first_name'].required = True
|
||||||
|
... self.fields['first_name'].widget.attrs['class'] = 'required'
|
||||||
... self.fields['last_name'].required = True
|
... self.fields['last_name'].required = True
|
||||||
|
... self.fields['last_name'].widget.attrs['class'] = 'required'
|
||||||
>>> f = Person(names_required=False)
|
>>> f = Person(names_required=False)
|
||||||
>>> f['first_name'].field.required, f['last_name'].field.required
|
>>> f['first_name'].field.required, f['last_name'].field.required
|
||||||
(False, False)
|
(False, False)
|
||||||
|
>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
|
||||||
|
({}, {})
|
||||||
>>> f = Person(names_required=True)
|
>>> f = Person(names_required=True)
|
||||||
>>> f['first_name'].field.required, f['last_name'].field.required
|
>>> f['first_name'].field.required, f['last_name'].field.required
|
||||||
(True, True)
|
(True, True)
|
||||||
|
>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
|
||||||
|
({'class': 'required'}, {'class': 'required'})
|
||||||
>>> f = Person(names_required=False)
|
>>> f = Person(names_required=False)
|
||||||
>>> f['first_name'].field.required, f['last_name'].field.required
|
>>> f['first_name'].field.required, f['last_name'].field.required
|
||||||
(False, False)
|
(False, False)
|
||||||
|
>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
|
||||||
|
({}, {})
|
||||||
>>> class Person(Form):
|
>>> class Person(Form):
|
||||||
... first_name = CharField(max_length=30)
|
... first_name = CharField(max_length=30)
|
||||||
... last_name = CharField(max_length=30)
|
... last_name = CharField(max_length=30)
|
||||||
|
@ -119,7 +119,7 @@ class AssertRedirectsTests(TestCase):
|
|||||||
try:
|
try:
|
||||||
self.assertRedirects(response, '/test_client/get_view/')
|
self.assertRedirects(response, '/test_client/get_view/')
|
||||||
except AssertionError, e:
|
except AssertionError, e:
|
||||||
self.assertEquals(str(e), "Response redirected to '/test_client/get_view/?var=value', expected '/test_client/get_view/'")
|
self.assertEquals(str(e), "Response redirected to 'http://testserver/test_client/get_view/?var=value', expected '/test_client/get_view/'")
|
||||||
|
|
||||||
def test_incorrect_target(self):
|
def test_incorrect_target(self):
|
||||||
"An assertion is raised if the response redirects to another target"
|
"An assertion is raised if the response redirects to another target"
|
||||||
@ -135,7 +135,7 @@ class AssertRedirectsTests(TestCase):
|
|||||||
response = self.client.get('/test_client/double_redirect_view/')
|
response = self.client.get('/test_client/double_redirect_view/')
|
||||||
try:
|
try:
|
||||||
# The redirect target responds with a 301 code, not 200
|
# The redirect target responds with a 301 code, not 200
|
||||||
self.assertRedirects(response, '/test_client/permanent_redirect_view/')
|
self.assertRedirects(response, 'http://testserver/test_client/permanent_redirect_view/')
|
||||||
except AssertionError, e:
|
except AssertionError, e:
|
||||||
self.assertEquals(str(e), "Couldn't retrieve redirection page '/test_client/permanent_redirect_view/': response code was 301 (expected 200)")
|
self.assertEquals(str(e), "Couldn't retrieve redirection page '/test_client/permanent_redirect_view/': response code was 301 (expected 200)")
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ class LoginTests(TestCase):
|
|||||||
# Create a second client, and log in.
|
# Create a second client, and log in.
|
||||||
c = Client()
|
c = Client()
|
||||||
login = c.login(username='testclient', password='password')
|
login = c.login(username='testclient', password='password')
|
||||||
self.assertTrue(login, 'Could not log in')
|
self.failUnless(login, 'Could not log in')
|
||||||
|
|
||||||
# Get a redirection page with the second client.
|
# Get a redirection page with the second client.
|
||||||
response = c.get("/test_client_regress/login_protected_redirect_view/")
|
response = c.get("/test_client_regress/login_protected_redirect_view/")
|
||||||
@ -260,4 +260,4 @@ class LoginTests(TestCase):
|
|||||||
# At this points, the self.client isn't logged in.
|
# At this points, the self.client isn't logged in.
|
||||||
# Check that assertRedirects uses the original client, not the
|
# Check that assertRedirects uses the original client, not the
|
||||||
# default client.
|
# default client.
|
||||||
self.assertRedirects(response, "/test_client_regress/get_view/")
|
self.assertRedirects(response, "http://testserver/test_client_regress/get_view/")
|
||||||
|
@ -4,11 +4,17 @@ import os, sys, traceback
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import django.contrib as contrib
|
import django.contrib as contrib
|
||||||
|
|
||||||
|
try:
|
||||||
|
set
|
||||||
|
except NameError:
|
||||||
|
from sets import Set as set # For Python 2.3
|
||||||
|
|
||||||
|
|
||||||
CONTRIB_DIR_NAME = 'django.contrib'
|
CONTRIB_DIR_NAME = 'django.contrib'
|
||||||
MODEL_TESTS_DIR_NAME = 'modeltests'
|
MODEL_TESTS_DIR_NAME = 'modeltests'
|
||||||
REGRESSION_TESTS_DIR_NAME = 'regressiontests'
|
REGRESSION_TESTS_DIR_NAME = 'regressiontests'
|
||||||
|
|
||||||
TEST_DATABASE_NAME = 'django_test_db'
|
|
||||||
TEST_TEMPLATE_DIR = 'templates'
|
TEST_TEMPLATE_DIR = 'templates'
|
||||||
|
|
||||||
CONTRIB_DIR = os.path.dirname(contrib.__file__)
|
CONTRIB_DIR = os.path.dirname(contrib.__file__)
|
||||||
@ -90,7 +96,6 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
old_middleware_classes = settings.MIDDLEWARE_CLASSES
|
old_middleware_classes = settings.MIDDLEWARE_CLASSES
|
||||||
|
|
||||||
# Redirect some settings for the duration of these tests.
|
# Redirect some settings for the duration of these tests.
|
||||||
settings.TEST_DATABASE_NAME = TEST_DATABASE_NAME
|
|
||||||
settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS
|
settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS
|
||||||
settings.ROOT_URLCONF = 'urls'
|
settings.ROOT_URLCONF = 'urls'
|
||||||
settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
|
settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
|
||||||
@ -143,7 +148,6 @@ def django_tests(verbosity, interactive, test_labels):
|
|||||||
|
|
||||||
# Restore the old settings.
|
# Restore the old settings.
|
||||||
settings.INSTALLED_APPS = old_installed_apps
|
settings.INSTALLED_APPS = old_installed_apps
|
||||||
settings.TESTS_DATABASE_NAME = old_test_database_name
|
|
||||||
settings.ROOT_URLCONF = old_root_urlconf
|
settings.ROOT_URLCONF = old_root_urlconf
|
||||||
settings.TEMPLATE_DIRS = old_template_dirs
|
settings.TEMPLATE_DIRS = old_template_dirs
|
||||||
settings.USE_I18N = old_use_i18n
|
settings.USE_I18N = old_use_i18n
|
||||||
|
Loading…
x
Reference in New Issue
Block a user