1
0
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:
Adrian Holovaty 2007-09-15 21:34:09 +00:00
parent fb6a0c8ffa
commit bf6a46d8ad
30 changed files with 347 additions and 111 deletions

View File

@ -246,6 +246,7 @@ answer newbie questions, and generally made Django that much better:
Brian Ray <http://brianray.chipy.org/>
remco@diji.biz
rhettg@gmail.com
Matt Riggott
Henrique Romano <onaiort@gmail.com>
Armin Ronacher
Brian Rosner <brosner@gmail.com>

View File

@ -14,7 +14,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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
msgid "object ID"

View File

@ -1,5 +1,9 @@
// 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.
function addEvent(obj, evType, fn) {
if (obj.addEventListener) {
@ -71,9 +75,13 @@ function findPosX(obj) {
var curleft = 0;
if (obj.offsetParent) {
while (obj.offsetParent) {
curleft += obj.offsetLeft;
curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft);
obj = obj.offsetParent;
}
// IE offsetParent does not include the top-level
if (isIE && obj.parentElement){
curleft += obj.offsetLeft - obj.scrollLeft;
}
} else if (obj.x) {
curleft += obj.x;
}
@ -84,9 +92,13 @@ function findPosY(obj) {
var curtop = 0;
if (obj.offsetParent) {
while (obj.offsetParent) {
curtop += obj.offsetTop;
curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop);
obj = obj.offsetParent;
}
// IE offsetParent does not include the top-level
if (isIE && obj.parentElement){
curtop += obj.offsetTop - obj.scrollTop;
}
} else if (obj.y) {
curtop += obj.y;
}

View File

@ -6,16 +6,21 @@ BR-specific Form helpers
from django.newforms import ValidationError
from django.newforms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext
from django.utils.translation import ugettext as _
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})$')
class BRZipCodeField(RegexField):
def __init__(self, *args, **kwargs):
super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
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)
class BRPhoneNumberField(Field):
@ -27,7 +32,7 @@ class BRPhoneNumberField(Field):
m = phone_digits_re.search(value)
if m:
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):
"""
@ -38,6 +43,32 @@ class BRStateSelect(Select):
from br_states import 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):
if v >= 2:
@ -69,9 +100,9 @@ class BRCPFField(CharField):
try:
int(value)
except ValueError:
raise ValidationError(ugettext("This field requires only numbers."))
raise ValidationError(_("This field requires only numbers."))
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:]
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)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
raise ValidationError(ugettext("Invalid CPF number."))
raise ValidationError(_("Invalid CPF number."))
return orig_value
@ -103,7 +134,7 @@ class BRCNPJField(Field):
raise ValidationError("This field requires only numbers.")
if len(value) != 14:
raise ValidationError(
ugettext("This field requires at least 14 digits"))
_("This field requires at least 14 digits"))
orig_dv = value[-2:]
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)
value = value[:-1] + str(new_2dv)
if value[-2:] != orig_dv:
raise ValidationError(ugettext("Invalid CNPJ number."))
raise ValidationError(_("Invalid CNPJ number."))
return orig_value

View File

@ -1,15 +1,33 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.http import get_host
SITE_CACHE = {}
class SiteManager(models.Manager):
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
try:
sid = settings.SITE_ID
except AttributeError:
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.")
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):
domain = models.CharField(_('domain name'), max_length=100)
@ -36,7 +54,7 @@ class RequestSite(object):
The save() and delete() methods raise NotImplementedError.
"""
def __init__(self, request):
self.domain = self.name = request.META['SERVER_NAME']
self.domain = self.name = get_host(request)
def __unicode__(self):
return self.domain

View File

@ -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)

View File

@ -50,6 +50,10 @@ class BaseHandler(object):
def get_response(self, request):
"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.mail import mail_admins
from django.conf import settings
@ -129,3 +133,16 @@ class BaseHandler(object):
"Helper function to return the traceback as a string"
import traceback
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

View File

@ -181,10 +181,15 @@ def isValidImage(field_data, all_data):
except TypeError:
raise ValidationError, _("No file was submitted. Check the encoding type on the form.")
try:
Image.open(StringIO(content))
except (IOError, OverflowError): # Python Imaging Library doesn't recognize it as an image
# OverflowError is due to a bug in PIL with Python 2.4+ which can cause
# it to gag on OLE files.
# load() is the only method that can spot a truncated JPEG,
# but it cannot be called sanely after verify()
trial_image = Image.open(StringIO(content))
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.")
def isValidImageURL(field_data, all_data):

View File

@ -241,10 +241,12 @@ class Model(object):
placeholders = ['%s'] * len(field_names)
if self._meta.order_with_respect_to:
field_names.append(qn('_order'))
# TODO: This assumes the database supports subqueries.
placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
(qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column)))
db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
placeholders.append('%s')
subsel = 'SELECT COUNT(*) FROM %s WHERE %s = %%s' % (
qn(self._meta.db_table),
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:
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
(qn(self._meta.db_table), ','.join(field_names),

View File

@ -2,6 +2,7 @@ import os
from Cookie import SimpleCookie
from pprint import pformat
from urllib import urlencode
from urlparse import urljoin
from django.utils.datastructures import MultiValueDict, FileDict
from django.utils.encoding import smart_str, iri_to_uri, force_unicode
@ -46,6 +47,20 @@ class HttpRequest(object):
def get_full_path(self):
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):
return os.environ.get("HTTPS") == "on"
@ -364,9 +379,16 @@ class HttpResponseServerError(HttpResponse):
def get_host(request):
"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', '')
if not host:
host = request.META.get('HTTP_HOST', '')
if 'HTTP_HOST' in request.META:
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
# It's neither necessary nor appropriate to use

View File

@ -2,6 +2,7 @@
Field classes
"""
import copy
import datetime
import re
import time
@ -100,6 +101,12 @@ class Field(object):
"""
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):
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
self.max_length, self.min_length = max_length, min_length
@ -386,10 +393,15 @@ class ImageField(FileField):
from PIL import Image
from cStringIO import StringIO
try:
Image.open(StringIO(f.content))
except (IOError, OverflowError): # Python Imaging Library doesn't recognize it as an image
# OverflowError is due to a bug in PIL with Python 2.4+ which can cause
# it to gag on OLE files.
# load() is the only method that can spot a truncated JPEG,
# but it cannot be called sanely after verify()
trial_image = Image.open(StringIO(f.content))
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."))
return f
@ -409,6 +421,9 @@ class URLField(RegexField):
self.user_agent = validator_user_agent
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)
if value == u'':
return value

View File

@ -31,7 +31,7 @@ class SortedDictFromList(SortedDict):
dict.__init__(self, dict(data))
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):
"""

View File

@ -84,12 +84,8 @@ class TestCase(unittest.TestCase):
self.assertEqual(response.status_code, status_code,
("Response didn't redirect as expected: Response code was %d"
" (expected %d)" % (response.status_code, status_code)))
scheme, netloc, path, query, fragment = urlsplit(response['Location'])
url = path
if query:
url += '?' + query
if fragment:
url += '#' + fragment
url = response['Location']
scheme, netloc, path, query, fragment = urlsplit(url)
self.assertEqual(url, expected_url,
"Response redirected to '%s', expected '%s'" % (url, expected_url))

View File

@ -10,7 +10,7 @@ from django.http import Http404, HttpResponse
def archive_index(request, queryset, date_field, num_latest=15,
template_name=None, template_loader=loader,
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.
@ -39,7 +39,7 @@ def archive_index(request, queryset, date_field, num_latest=15,
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'date_list' : date_list,
'latest' : latest,
template_object_name : latest,
}, context_processors)
for key, value in extra_context.items():
if callable(value):

View File

@ -9,20 +9,26 @@ def set_language(request):
"""
Redirect to a given url while setting the chosen language in the
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)
if not next:
next = request.META.get('HTTP_REFERER', None)
if not next:
next = '/'
response = http.HttpResponseRedirect(next)
if lang_code and check_for_language(lang_code):
if hasattr(request, 'session'):
request.session['django_language'] = lang_code
else:
response.set_cookie('django_language', lang_code)
if request.method == 'POST':
lang_code = request.POST.get('language', None)
if lang_code and check_for_language(lang_code):
if hasattr(request, 'session'):
request.session['django_language'] = lang_code
else:
response.set_cookie('django_language', lang_code)
return response
NullSource = """

View File

@ -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'])
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
---------------------------------------------

View File

@ -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
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:**
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
ordered in reverse. This is equivalent to
``queryset.dates(date_field, 'year')[::-1]``.
* ``latest``: The ``num_latest`` objects in the system, ordered descending
by ``date_field``. For example, if ``num_latest`` is ``10``, then
``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
``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
page.
* ``page_range``: A list of the page numbers that are available. This
is 1-based.
* **New in Django development version:** ``page_range``: A list of the
page numbers that are available. This is 1-based.
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.
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``::
/objects/?page=last

View File

@ -127,16 +127,24 @@ Installing an official release
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``
directory.
These commands will install Django in your Python installation's
``site-packages`` directory.
.. _distribution specific notes: ../distributions/
.. _bsdtar: http://gnuwin32.sourceforge.net/packages/bsdtar.htm
.. _7-zip: http://www.7-zip.org/
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
latest bug fixes and improvements, follow these instructions:
1. Make sure you have Subversion_ installed.
2. Check out the Django code into your Python ``site-packages`` directory.
1. Make sure that you have Subversion_ installed, and that you can run its
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
ln -s `pwd`/django_src/django SITE-PACKAGES-DIR/django
svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
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
your system's ``site-packages`` directory, as explained in the
"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
system path, such as ``/usr/local/bin`` (Unix) or ``C:\Python24\Scripts``
If you take the approach of setting ``PYTHONPATH``, you'll need to
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
any directory, rather than having to qualify the command with the full path
to the file.
You *don't* have to run ``python setup.py install``, because that command
takes care of steps 2 and 3 for you.
You *don't* have to run ``python setup.py install``, because you've already
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
command ``svn update`` from within the ``django`` directory. When you do this,
Subversion will automatically download any changes.
command ``svn update`` from within the ``django-trunk`` directory. When you do
this, Subversion will automatically download any changes.
.. _`download page`: http://www.djangoproject.com/download/
.. _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

View File

@ -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
page of the admin. This should be a list of field names, and each specified
field should be either a ``BooleanField``, ``DateField``, ``DateTimeField``
or ``ForeignKey``.
field should be either a ``BooleanField``, ``CharField``, ``DateField``,
``DateTimeField``, ``IntegerField`` or ``ForeignKey``.
This example, taken from the ``django.contrib.auth.models.User`` model, shows
how both ``list_display`` and ``list_filter`` work::

View File

@ -83,7 +83,7 @@ need to write your ``PythonPath`` directive as::
With this path, ``import weblog`` and ``import mysite.settings`` will both
work. If you had ``import blogroll`` in your code somewhere and ``blogroll``
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
path.

View File

@ -161,6 +161,18 @@ Methods
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()``
Returns ``True`` if the request is secure; that is, if it was made with
HTTPS.
@ -184,8 +196,8 @@ subclass of dictionary. Exceptions are outlined here:
* ``__getitem__(key)`` -- Returns the value for the given key. If the key
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``).
does not exist. (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]``
(a Python list whose single element is ``value``). Note that this, as

View File

@ -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://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``
==========================

View File

@ -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
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/

View File

@ -642,12 +642,12 @@ your function. Example::
"Converts a string into all lowercase"
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
argument, you should use the included decorator ``stringfilter``. This will
convert an object to it's string value before being passed to your function::
If you're writing a template filter that only expects a string as the first
argument, you should use the decorator ``stringfilter``. This will
convert an object to its string value before being passed to your function::
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):
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -83,23 +83,31 @@ class ClientTest(TestCase):
def test_redirect(self):
"GET a URL that redirects elsewhere"
response = self.client.get('/test_client/redirect_view/')
# 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):
"GET a URL that redirects with given GET parameters"
response = self.client.get('/test_client/redirect_view/', {'var': 'value'})
# 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):
"GET a URL that redirects permanently elsewhere"
response = self.client.get('/test_client/permanent_redirect_view/')
# 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):
"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
# 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):
"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.
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
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
response = self.client.get('/test_client/login_protected_view/')
@ -269,7 +277,7 @@ class ClientTest(TestCase):
# Request a page that requires a login
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):
"Request a page that modifies the session"

View File

@ -980,6 +980,20 @@ u'41-3562-3464'
>>> 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>'
# 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 ##############################################################
>>> from django.contrib.localflavor.de.forms import DEZipCodeField

View File

@ -1623,10 +1623,6 @@ u'http://200.8.9.10:8000/test'
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid URL.']
>>> f.clean('example.com')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid URL.']
>>> f.clean('http://')
Traceback (most recent call last):
...
@ -1657,10 +1653,6 @@ u'http://www.example.com'
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid URL.']
>>> f.clean('example.com')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid URL.']
>>> f.clean('http://')
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).']
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 ################################################################
>>> f = BooleanField()
@ -2690,16 +2691,24 @@ to the next.
... super(Person, self).__init__(*args, **kwargs)
... if names_required:
... self.fields['first_name'].required = True
... self.fields['first_name'].widget.attrs['class'] = 'required'
... self.fields['last_name'].required = True
... self.fields['last_name'].widget.attrs['class'] = 'required'
>>> f = Person(names_required=False)
>>> f['first_name'].field.required, f['last_name'].field.required
(False, False)
>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
({}, {})
>>> f = Person(names_required=True)
>>> f['first_name'].field.required, f['last_name'].field.required
(True, True)
>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
({'class': 'required'}, {'class': 'required'})
>>> f = Person(names_required=False)
>>> f['first_name'].field.required, f['last_name'].field.required
(False, False)
>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
({}, {})
>>> class Person(Form):
... first_name = CharField(max_length=30)
... last_name = CharField(max_length=30)

View File

@ -119,7 +119,7 @@ class AssertRedirectsTests(TestCase):
try:
self.assertRedirects(response, '/test_client/get_view/')
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):
"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/')
try:
# 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:
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.
c = Client()
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.
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.
# Check that assertRedirects uses the original client, not the
# default client.
self.assertRedirects(response, "/test_client_regress/get_view/")
self.assertRedirects(response, "http://testserver/test_client_regress/get_view/")

View File

@ -4,11 +4,17 @@ import os, sys, traceback
import unittest
import django.contrib as contrib
try:
set
except NameError:
from sets import Set as set # For Python 2.3
CONTRIB_DIR_NAME = 'django.contrib'
MODEL_TESTS_DIR_NAME = 'modeltests'
REGRESSION_TESTS_DIR_NAME = 'regressiontests'
TEST_DATABASE_NAME = 'django_test_db'
TEST_TEMPLATE_DIR = 'templates'
CONTRIB_DIR = os.path.dirname(contrib.__file__)
@ -90,7 +96,6 @@ def django_tests(verbosity, interactive, test_labels):
old_middleware_classes = settings.MIDDLEWARE_CLASSES
# Redirect some settings for the duration of these tests.
settings.TEST_DATABASE_NAME = TEST_DATABASE_NAME
settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS
settings.ROOT_URLCONF = 'urls'
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.
settings.INSTALLED_APPS = old_installed_apps
settings.TESTS_DATABASE_NAME = old_test_database_name
settings.ROOT_URLCONF = old_root_urlconf
settings.TEMPLATE_DIRS = old_template_dirs
settings.USE_I18N = old_use_i18n