1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[multi-db] Merge trunk to [3257]

git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3258 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jason Pellerin 2006-07-03 14:23:39 +00:00
parent 4190c9e16f
commit 1c6199dc87
32 changed files with 1485 additions and 175 deletions

View File

@ -67,6 +67,10 @@ LANGUAGES = (
# Languages using BiDi (right-to-left) layout
LANGUAGES_BIDI = ("he",)
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# Not-necessarily-technical managers of the site. They get broken link
# notifications and other various e-mails.
MANAGERS = ADMINS

View File

@ -43,7 +43,7 @@
</div>
<!-- END Content -->
<div id="footer"></div>
{% block footer %}<div id="footer"></div>{% endblock %}
</div>
<!-- END Container -->

View File

@ -1,9 +1,15 @@
from django.conf import settings
from django.conf.urls.defaults import *
if settings.USE_I18N:
i18n_view = 'django.views.i18n.javascript_catalog'
else:
i18n_view = 'django.views.i18n.null_javascript_catalog'
urlpatterns = patterns('',
('^$', 'django.contrib.admin.views.main.index'),
('^r/(\d+)/(.*)/$', 'django.views.defaults.shortcut'),
('^jsi18n/$', 'django.views.i18n.javascript_catalog', {'packages': 'django.conf'}),
('^jsi18n/$', i18n_view, {'packages': 'django.conf'}),
('^logout/$', 'django.contrib.auth.views.logout'),
('^password_change/$', 'django.contrib.auth.views.password_change'),
('^password_change/done/$', 'django.contrib.auth.views.password_change_done'),
@ -29,3 +35,5 @@ urlpatterns = patterns('',
('^([^/]+)/([^/]+)/(.+)/delete/$', 'django.contrib.admin.views.main.delete_stage'),
('^([^/]+)/([^/]+)/(.+)/$', 'django.contrib.admin.views.main.change_stage'),
)
del i18n_view

View File

@ -27,17 +27,17 @@ def get_backends():
def authenticate(**credentials):
"""
If the given credentials, return a user object.
If the given credentials are valid, return a User object.
"""
for backend in get_backends():
try:
user = backend.authenticate(**credentials)
except TypeError:
# this backend doesn't accept these credentials as arguments, try the next one.
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
if user is None:
continue
# annotate the user object with the path of the backend
# Annotate the user object with the path of the backend.
user.backend = str(backend.__class__)
return user
@ -54,7 +54,7 @@ def login(request, user):
def logout(request):
"""
Remove the authenticated user's id from request.
Remove the authenticated user's ID from the request.
"""
del request.session[SESSION_KEY]
del request.session[BACKEND_SESSION_KEY]

View File

@ -47,7 +47,8 @@ def restructuredtext(value):
raise template.TemplateSyntaxError, "Error in {% restructuredtext %} filter: The Python docutils library isn't installed."
return value
else:
parts = publish_parts(source=value, writer_name="html4css1")
docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
parts = publish_parts(source=value, writer_name="html4css1", settings_overrides=docutils_settings)
return parts["fragment"]
register.filter(textile)

View File

@ -20,7 +20,9 @@ from django.conf import settings
# Built-in serializers
BUILTIN_SERIALIZERS = {
"xml" : "django.core.serializers.xml_serializer",
"xml" : "django.core.serializers.xml_serializer",
"python" : "django.core.serializers.python",
"json" : "django.core.serializers.json",
}
_serializers = {}

View File

@ -33,7 +33,9 @@ class Serializer(object):
for obj in queryset:
self.start_object(obj)
for field in obj._meta.fields:
if field.rel is None:
if field is obj._meta.pk:
continue
elif field.rel is None:
self.handle_field(obj, field)
else:
self.handle_fk_field(obj, field)

View File

@ -0,0 +1,51 @@
"""
Serialize data to/from JSON
"""
import datetime
from django.utils import simplejson
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
class Serializer(PythonSerializer):
"""
Convert a queryset to JSON.
"""
def end_serialization(self):
simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder)
def getvalue(self):
return self.stream.getvalue()
def Deserializer(stream_or_string, **options):
"""
Deserialize a stream or string of JSON data.
"""
if isinstance(stream_or_string, basestring):
stream = StringIO(stream_or_string)
else:
stream = stream_or_string
for obj in PythonDeserializer(simplejson.load(stream)):
yield obj
class DateTimeAwareJSONEncoder(simplejson.JSONEncoder):
"""
JSONEncoder subclass that knows how to encode date/time types
"""
DATE_FORMAT = "%Y-%m-%d"
TIME_FORMAT = "%H:%M:%S"
def default(self, o):
if isinstance(o, datetime.date):
return o.strftime(self.DATE_FORMAT)
elif isinstance(o, datetime.time):
return o.strftime(self.TIME_FORMAT)
elif isinstance(o, datetime.datetime):
return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT))
else:
return super(self, DateTimeAwareJSONEncoder).default(o)

View File

@ -0,0 +1,101 @@
"""
A Python "serializer". Doesn't do much serializing per se -- just converts to
and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
other serializers.
"""
from django.conf import settings
from django.core.serializers import base
from django.db import models
class Serializer(base.Serializer):
"""
Serializes a QuerySet to basic Python objects.
"""
def start_serialization(self):
self._current = None
self.objects = []
def end_serialization(self):
pass
def start_object(self, obj):
self._current = {}
def end_object(self, obj):
self.objects.append({
"model" : str(obj._meta),
"pk" : str(obj._get_pk_val()),
"fields" : self._current
})
self._current = None
def handle_field(self, obj, field):
self._current[field.name] = getattr(obj, field.name)
def handle_fk_field(self, obj, field):
related = getattr(obj, field.name)
if related is not None:
related = related._get_pk_val()
self._current[field.name] = related
def handle_m2m_field(self, obj, field):
self._current[field.name] = [related._get_pk_val() for related in getattr(obj, field.name).iterator()]
def getvalue(self):
return self.objects
def Deserializer(object_list, **options):
"""
Deserialize simple Python objects back into Django ORM instances.
It's expected that you pass the Python objects themselves (instead of a
stream or a string) to the constructor
"""
models.get_apps()
for d in object_list:
# Look up the model and starting build a dict of data for it.
Model = _get_model(d["model"])
data = {Model._meta.pk.name : d["pk"]}
m2m_data = {}
# Handle each field
for (field_name, field_value) in d["fields"].iteritems():
if isinstance(field_value, unicode):
field_value = field_value.encode(options.get("encoding", settings.DEFAULT_CHARSET))
field = Model._meta.get_field(field_name)
# Handle M2M relations (with in_bulk() for performance)
if field.rel and isinstance(field.rel, models.ManyToManyRel):
pks = []
for pk in field_value:
if isinstance(pk, unicode):
pk = pk.encode(options.get("encoding", settings.DEFAULT_CHARSET))
m2m_data[field.name] = field.rel.to._default_manager.in_bulk(field_value).values()
# Handle FK fields
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
try:
data[field.name] = field.rel.to._default_manager.get(pk=field_value)
except RelatedModel.DoesNotExist:
data[field.name] = None
# Handle all other fields
else:
data[field.name] = field.to_python(field_value)
yield base.DeserializedObject(Model(**data), m2m_data)
def _get_model(model_identifier):
"""
Helper to look up a model from an "app_label.module_name" string.
"""
try:
Model = models.get_model(*model_identifier.split("."))
except TypeError:
Model = None
if Model is None:
raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)
return Model

View File

@ -2,10 +2,11 @@
XML serializer.
"""
from xml.dom import pulldom
from django.utils.xmlutils import SimplerXMLGenerator
from django.conf import settings
from django.core.serializers import base
from django.db import models
from django.utils.xmlutils import SimplerXMLGenerator
from xml.dom import pulldom
class Serializer(base.Serializer):
"""
@ -16,7 +17,7 @@ class Serializer(base.Serializer):
"""
Start serialization -- open the XML document and the root element.
"""
self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", "utf-8"))
self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
self.xml.startDocument()
self.xml.startElement("django-objects", {"version" : "1.0"})
@ -58,9 +59,7 @@ class Serializer(base.Serializer):
# Get a "string version" of the object's data (this is handled by the
# serializer base class). None is handled specially.
value = self.get_string_value(obj, field)
if value is None:
self.xml.addQuickElement("None")
else:
if value is not None:
self.xml.characters(str(value))
self.xml.endElement("field")
@ -106,7 +105,7 @@ class Deserializer(base.Deserializer):
def __init__(self, stream_or_string, **options):
super(Deserializer, self).__init__(stream_or_string, **options)
self.encoding = self.options.get("encoding", "utf-8")
self.encoding = self.options.get("encoding", settings.DEFAULT_CHARSET)
self.event_stream = pulldom.parse(self.stream)
def next(self):

View File

@ -123,7 +123,6 @@ OPERATOR_MAPPING = {
'iexact': 'LIKE %s',
'contains': 'LIKE %s',
'icontains': 'LIKE %s',
'ne': '!= %s',
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',

View File

@ -6,7 +6,7 @@ from django import forms
from django.core.exceptions import ObjectDoesNotExist
from django.utils.functional import curry, lazy
from django.utils.text import capfirst
from django.utils.translation import gettext, gettext_lazy, ngettext
from django.utils.translation import gettext, gettext_lazy
import datetime, os, time
class NOT_PROVIDED:
@ -162,7 +162,7 @@ class Field(object):
def get_db_prep_lookup(self, lookup_type, value):
"Returns field's value prepared for database lookup."
if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'year', 'month', 'day', 'search'):
if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'year', 'month', 'day', 'search'):
return [value]
elif lookup_type in ('range', 'in'):
return value
@ -406,12 +406,15 @@ class DateField(Field):
if isinstance(value, datetime.date):
return value
validators.isValidANSIDate(value, None)
return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
try:
return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
except ValueError:
raise validators.ValidationError, gettext('Enter a valid date in YYYY-MM-DD format.')
def get_db_prep_lookup(self, lookup_type, value):
if lookup_type == 'range':
value = [str(v) for v in value]
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne') and hasattr(value, 'strftime'):
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
value = value.strftime('%Y-%m-%d')
else:
value = str(value)

View File

@ -78,6 +78,32 @@ class RelatedField(object):
related = RelatedObject(other, cls, self)
self.contribute_to_related_class(other, related)
def get_db_prep_lookup(self, lookup_type, value):
# If we are doing a lookup on a Related Field, we must be
# comparing object instances. The value should be the PK of value,
# not value itself.
def pk_trace(value):
# Value may be a primary key, or an object held in a relation.
# If it is an object, then we need to get the primary key value for
# that object. In certain conditions (especially one-to-one relations),
# the primary key may itself be an object - so we need to keep drilling
# down until we hit a value that can be used for a comparison.
v = value
try:
while True:
v = getattr(v, v._meta.pk.name)
except AttributeError:
pass
return v
if lookup_type == 'exact':
return [pk_trace(value)]
if lookup_type == 'in':
return [pk_trace(v) for v in value]
elif lookup_type == 'isnull':
return []
raise TypeError, "Related Field has invalid lookup: %s" % lookup_type
def _get_related_query_name(self, opts):
# This method defines the name that can be used to identify this related object
# in a table-spanning query. It uses the lower-cased object_name by default,

View File

@ -15,7 +15,7 @@ _app_models = {} # Dictionary of models against app label
_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
# Key is the app_name of the model, value is the exception that was raised
# during model loading.
_loaded = False # Has the contents of settings.INSTALLED_APPS been loaded?
_loaded = False # Has the contents of settings.INSTALLED_APPS been loaded?
# i.e., has get_apps() been called?
def get_apps():
@ -60,7 +60,7 @@ def get_app_errors():
global _app_errors
get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
return _app_errors
def get_models(app_mod=None):
"""
Given a module containing models, returns a list of the models. Otherwise

View File

@ -10,8 +10,17 @@ import re
if not hasattr(__builtins__, 'set'):
from sets import Set as set
# The string constant used to separate query parts
LOOKUP_SEPARATOR = '__'
# The list of valid query types
QUERY_TERMS = (
'exact', 'iexact', 'contains', 'icontains',
'gt', 'gte', 'lt', 'lte', 'in',
'startswith', 'istartswith', 'endswith', 'iendswith',
'range', 'year', 'month', 'day', 'isnull',
)
# Size of each "chunk" for get_iterator calls.
# Larger values are slightly faster at the expense of more storage space.
GET_ITERATOR_CHUNK_SIZE = 100
@ -206,7 +215,7 @@ class QuerySet(object):
raise self.model.DoesNotExist, "%s matching query does not exist." % self.model._meta.object_name
assert len(obj_list) == 1, "get() returned more than one %s -- it returned %s! Lookup parameters were %s" % (self.model._meta.object_name, len(obj_list), kwargs)
return obj_list[0]
def create(self, **kwargs):
"""
Create a new object with the given kwargs, saving it to the database
@ -723,12 +732,13 @@ def parse_lookup(kwarg_items, opts):
# if we find "pk", make the clause "exact', and insert
# a dummy name of None, which we will replace when
# we know which table column to grab as the primary key.
# 2) If there is only one part, assume it to be an __exact
# 2) If there is only one part, or the last part is not a query
# term, assume that the query is an __exact
clause = path.pop()
if clause == 'pk':
clause = 'exact'
path.append(None)
elif len(path) == 0:
elif len(path) == 0 or clause not in QUERY_TERMS:
path.append(clause)
clause = 'exact'
@ -857,12 +867,14 @@ def lookup_inner(path, clause, value, opts, table, column):
)
if path:
# There are elements left in the path. More joins are required.
if len(path) == 1 and path[0] in (new_opts.pk.name, None) \
and clause in ('exact', 'isnull') and not join_required:
# If the last name query is for a key, and the search is for
# isnull/exact, then the current (for N-1) or intermediate
# (for N-N) table can be used for the search - no need to join an
# extra table just to check the primary key.
# If the next and final name query is for a primary key,
# and the search is for isnull/exact, then the current
# (for N-1) or intermediate (for N-N) table can be used
# for the search - no need to join an extra table just
# to check the primary key.
new_table = current_table
else:
# There are 1 or more name queries pending, and we have ruled out
@ -888,13 +900,41 @@ def lookup_inner(path, clause, value, opts, table, column):
where.extend(where2)
params.extend(params2)
else:
# Evaluate clause on current table.
if name in (current_opts.pk.name, None) and clause in ('exact', 'isnull') and current_column:
# If this is an exact/isnull key search, and the last pass
# found/introduced a current/intermediate table that we can use to
# optimize the query, then use that column name.
# No elements left in path. Current element is the element on which
# the search is being performed.
if join_required:
# Last query term is a RelatedObject
if field.field.rel.multiple:
# RelatedObject is from a 1-N relation.
# Join is required; query operates on joined table.
column = new_opts.pk.name
joins[backend.quote_name(new_table)] = (
backend.quote_name(new_opts.db_table),
"INNER JOIN",
"%s.%s = %s.%s" %
(backend.quote_name(current_table),
backend.quote_name(join_column),
backend.quote_name(new_table),
backend.quote_name(new_column))
)
current_table = new_table
else:
# RelatedObject is from a 1-1 relation,
# No need to join; get the pk value from the related object,
# and compare using that.
column = current_opts.pk.name
elif intermediate_table:
# Last query term is a related object from an N-N relation.
# Join from intermediate table is sufficient.
column = join_column
elif name == current_opts.pk.name and clause in ('exact', 'isnull') and current_column:
# Last query term is for a primary key. If previous iterations
# introduced a current/intermediate table that can be used to
# optimize the query, then use that table and column name.
column = current_column
else:
# Last query term was a normal field.
column = field.column
where.append(get_where_clause(current_opts, clause, current_table + '.', column, value))

View File

@ -70,6 +70,10 @@ class RelatedObject(object):
else:
return [None] * self.field.rel.num_in_admin
def get_db_prep_lookup(self, lookup_type, value):
# Defer to the actual field definition for db prep
return self.field.get_db_prep_lookup(lookup_type, value)
def editable_fields(self):
"Get the fields in this class that should be edited inline."
return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field]

View File

@ -0,0 +1,20 @@
simplejson 1.3
Copyright (c) 2006 Bob Ippolito
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,221 @@
r"""
A simple, fast, extensible JSON encoder and decoder
JSON (JavaScript Object Notation) <http://json.org> is a subset of
JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
interchange format.
simplejson exposes an API familiar to uses of the standard library
marshal and pickle modules.
Encoding basic Python object hierarchies::
>>> import simplejson
>>> simplejson.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print simplejson.dumps("\"foo\bar")
"\"foo\bar"
>>> print simplejson.dumps(u'\u1234')
"\u1234"
>>> print simplejson.dumps('\\')
"\\"
>>> print simplejson.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
{"a": 0, "b": 0, "c": 0}
>>> from StringIO import StringIO
>>> io = StringIO()
>>> simplejson.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'
Decoding JSON::
>>> import simplejson
>>> simplejson.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
[u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
>>> simplejson.loads('"\\"foo\\bar"')
u'"foo\x08ar'
>>> from StringIO import StringIO
>>> io = StringIO('["streaming API"]')
>>> simplejson.load(io)
[u'streaming API']
Specializing JSON object decoding::
>>> import simplejson
>>> def as_complex(dct):
... if '__complex__' in dct:
... return complex(dct['real'], dct['imag'])
... return dct
...
>>> simplejson.loads('{"__complex__": true, "real": 1, "imag": 2}',
... object_hook=as_complex)
(1+2j)
Extending JSONEncoder::
>>> import simplejson
>>> class ComplexEncoder(simplejson.JSONEncoder):
... def default(self, obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... return simplejson.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']
Note that the JSON produced by this module is a subset of YAML,
so it may be used as a serializer for that as well.
"""
__version__ = '1.3'
__all__ = [
'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONEncoder',
]
from django.utils.simplejson.decoder import JSONDecoder
from django.utils.simplejson.encoder import JSONEncoder
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, **kw):
"""
Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
``.write()``-supporting file-like object).
If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.
If ``ensure_ascii`` is ``False``, then the some chunks written to ``fp``
may be ``unicode`` instances, subject to normal Python ``str`` to
``unicode`` coercion rules. Unless ``fp.write()`` explicitly
understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
to cause an error.
If ``check_circular`` is ``False``, then the circular reference check
for container types will be skipped and a circular reference will
result in an ``OverflowError`` (or worse).
If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
in strict compliance of the JSON specification, instead of using the
JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg.
"""
if cls is None:
cls = JSONEncoder
iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan,
**kw).iterencode(obj)
# could accelerate with writelines in some versions of Python, at
# a debuggability cost
for chunk in iterable:
fp.write(chunk)
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, **kw):
"""
Serialize ``obj`` to a JSON formatted ``str``.
If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.
If ``ensure_ascii`` is ``False``, then the return value will be a
``unicode`` instance subject to normal Python ``str`` to ``unicode``
coercion rules instead of being escaped to an ASCII ``str``.
If ``check_circular`` is ``False``, then the circular reference check
for container types will be skipped and a circular reference will
result in an ``OverflowError`` (or worse).
If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
strict compliance of the JSON specification, instead of using the
JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg.
"""
if cls is None:
cls = JSONEncoder
return cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, **kw).encode(obj)
def load(fp, encoding=None, cls=None, object_hook=None, **kw):
"""
Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
a JSON document) to a Python object.
If the contents of ``fp`` is encoded with an ASCII based encoding other
than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must
be specified. Encodings that are not ASCII based (such as UCS-2) are
not allowed, and should be wrapped with
``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode``
object and passed to ``loads()``
``object_hook`` is an optional function that will be called with the
result of any object literal decode (a ``dict``). The return value of
``object_hook`` will be used instead of the ``dict``. This feature
can be used to implement custom decoders (e.g. JSON-RPC class hinting).
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
kwarg.
"""
if cls is None:
cls = JSONDecoder
if object_hook is not None:
kw['object_hook'] = object_hook
return cls(encoding=encoding, **kw).decode(fp.read())
def loads(s, encoding=None, cls=None, object_hook=None, **kw):
"""
Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
document) to a Python object.
If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding
other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name
must be specified. Encodings that are not ASCII based (such as UCS-2)
are not allowed and should be decoded to ``unicode`` first.
``object_hook`` is an optional function that will be called with the
result of any object literal decode (a ``dict``). The return value of
``object_hook`` will be used instead of the ``dict``. This feature
can be used to implement custom decoders (e.g. JSON-RPC class hinting).
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
kwarg.
"""
if cls is None:
cls = JSONDecoder
if object_hook is not None:
kw['object_hook'] = object_hook
return cls(encoding=encoding, **kw).decode(s)
def read(s):
"""
json-py API compatibility hook. Use loads(s) instead.
"""
import warnings
warnings.warn("simplejson.loads(s) should be used instead of read(s)",
DeprecationWarning)
return loads(s)
def write(obj):
"""
json-py API compatibility hook. Use dumps(s) instead.
"""
import warnings
warnings.warn("simplejson.dumps(s) should be used instead of write(s)",
DeprecationWarning)
return dumps(obj)

View File

@ -0,0 +1,271 @@
"""
Implementation of JSONDecoder
"""
import re
from django.utils.simplejson.scanner import Scanner, pattern
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
def _floatconstants():
import struct
import sys
_BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
if sys.byteorder != 'big':
_BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
nan, inf = struct.unpack('dd', _BYTES)
return nan, inf, -inf
NaN, PosInf, NegInf = _floatconstants()
def linecol(doc, pos):
lineno = doc.count('\n', 0, pos) + 1
if lineno == 1:
colno = pos
else:
colno = pos - doc.rindex('\n', 0, pos)
return lineno, colno
def errmsg(msg, doc, pos, end=None):
lineno, colno = linecol(doc, pos)
if end is None:
return '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos)
endlineno, endcolno = linecol(doc, end)
return '%s: line %d column %d - line %d column %d (char %d - %d)' % (
msg, lineno, colno, endlineno, endcolno, pos, end)
_CONSTANTS = {
'-Infinity': NegInf,
'Infinity': PosInf,
'NaN': NaN,
'true': True,
'false': False,
'null': None,
}
def JSONConstant(match, context, c=_CONSTANTS):
return c[match.group(0)], None
pattern('(-?Infinity|NaN|true|false|null)')(JSONConstant)
def JSONNumber(match, context):
match = JSONNumber.regex.match(match.string, *match.span())
integer, frac, exp = match.groups()
if frac or exp:
res = float(integer + (frac or '') + (exp or ''))
else:
res = int(integer)
return res, None
pattern(r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?')(JSONNumber)
STRINGCHUNK = re.compile(r'(.*?)(["\\])', FLAGS)
BACKSLASH = {
'"': u'"', '\\': u'\\', '/': u'/',
'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t',
}
DEFAULT_ENCODING = "utf-8"
def scanstring(s, end, encoding=None, _b=BACKSLASH, _m=STRINGCHUNK.match):
if encoding is None:
encoding = DEFAULT_ENCODING
chunks = []
_append = chunks.append
begin = end - 1
while 1:
chunk = _m(s, end)
if chunk is None:
raise ValueError(
errmsg("Unterminated string starting at", s, begin))
end = chunk.end()
content, terminator = chunk.groups()
if content:
if not isinstance(content, unicode):
content = unicode(content, encoding)
_append(content)
if terminator == '"':
break
try:
esc = s[end]
except IndexError:
raise ValueError(
errmsg("Unterminated string starting at", s, begin))
if esc != 'u':
try:
m = _b[esc]
except KeyError:
raise ValueError(
errmsg("Invalid \\escape: %r" % (esc,), s, end))
end += 1
else:
esc = s[end + 1:end + 5]
try:
m = unichr(int(esc, 16))
if len(esc) != 4 or not esc.isalnum():
raise ValueError
except ValueError:
raise ValueError(errmsg("Invalid \\uXXXX escape", s, end))
end += 5
_append(m)
return u''.join(chunks), end
def JSONString(match, context):
encoding = getattr(context, 'encoding', None)
return scanstring(match.string, match.end(), encoding)
pattern(r'"')(JSONString)
WHITESPACE = re.compile(r'\s*', FLAGS)
def JSONObject(match, context, _w=WHITESPACE.match):
pairs = {}
s = match.string
end = _w(s, match.end()).end()
nextchar = s[end:end + 1]
# trivial empty object
if nextchar == '}':
return pairs, end + 1
if nextchar != '"':
raise ValueError(errmsg("Expecting property name", s, end))
end += 1
encoding = getattr(context, 'encoding', None)
while True:
key, end = scanstring(s, end, encoding)
end = _w(s, end).end()
if s[end:end + 1] != ':':
raise ValueError(errmsg("Expecting : delimiter", s, end))
end = _w(s, end + 1).end()
try:
value, end = JSONScanner.iterscan(s, idx=end).next()
except StopIteration:
raise ValueError(errmsg("Expecting object", s, end))
pairs[key] = value
end = _w(s, end).end()
nextchar = s[end:end + 1]
end += 1
if nextchar == '}':
break
if nextchar != ',':
raise ValueError(errmsg("Expecting , delimiter", s, end - 1))
end = _w(s, end).end()
nextchar = s[end:end + 1]
end += 1
if nextchar != '"':
raise ValueError(errmsg("Expecting property name", s, end - 1))
object_hook = getattr(context, 'object_hook', None)
if object_hook is not None:
pairs = object_hook(pairs)
return pairs, end
pattern(r'{')(JSONObject)
def JSONArray(match, context, _w=WHITESPACE.match):
values = []
s = match.string
end = _w(s, match.end()).end()
# look-ahead for trivial empty array
nextchar = s[end:end + 1]
if nextchar == ']':
return values, end + 1
while True:
try:
value, end = JSONScanner.iterscan(s, idx=end).next()
except StopIteration:
raise ValueError(errmsg("Expecting object", s, end))
values.append(value)
end = _w(s, end).end()
nextchar = s[end:end + 1]
end += 1
if nextchar == ']':
break
if nextchar != ',':
raise ValueError(errmsg("Expecting , delimiter", s, end))
end = _w(s, end).end()
return values, end
pattern(r'\[')(JSONArray)
ANYTHING = [
JSONObject,
JSONArray,
JSONString,
JSONConstant,
JSONNumber,
]
JSONScanner = Scanner(ANYTHING)
class JSONDecoder(object):
"""
Simple JSON <http://json.org> decoder
Performs the following translations in decoding:
+---------------+-------------------+
| JSON | Python |
+===============+===================+
| object | dict |
+---------------+-------------------+
| array | list |
+---------------+-------------------+
| string | unicode |
+---------------+-------------------+
| number (int) | int, long |
+---------------+-------------------+
| number (real) | float |
+---------------+-------------------+
| true | True |
+---------------+-------------------+
| false | False |
+---------------+-------------------+
| null | None |
+---------------+-------------------+
It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
their corresponding ``float`` values, which is outside the JSON spec.
"""
_scanner = Scanner(ANYTHING)
__all__ = ['__init__', 'decode', 'raw_decode']
def __init__(self, encoding=None, object_hook=None):
"""
``encoding`` determines the encoding used to interpret any ``str``
objects decoded by this instance (utf-8 by default). It has no
effect when decoding ``unicode`` objects.
Note that currently only encodings that are a superset of ASCII work,
strings of other encodings should be passed in as ``unicode``.
``object_hook``, if specified, will be called with the result
of every JSON object decoded and its return value will be used in
place of the given ``dict``. This can be used to provide custom
deserializations (e.g. to support JSON-RPC class hinting).
"""
self.encoding = encoding
self.object_hook = object_hook
def decode(self, s, _w=WHITESPACE.match):
"""
Return the Python representation of ``s`` (a ``str`` or ``unicode``
instance containing a JSON document)
"""
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
end = _w(s, end).end()
if end != len(s):
raise ValueError(errmsg("Extra data", s, end, len(s)))
return obj
def raw_decode(self, s, **kw):
"""
Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning
with a JSON document) and return a 2-tuple of the Python
representation and the index in ``s`` where the document ended.
This can be used to decode a JSON document from a string that may
have extraneous data at the end.
"""
kw.setdefault('context', self)
try:
obj, end = self._scanner.iterscan(s, **kw).next()
except StopIteration:
raise ValueError("No JSON object could be decoded")
return obj, end
__all__ = ['JSONDecoder']

View File

@ -0,0 +1,289 @@
"""
Implementation of JSONEncoder
"""
import re
# this should match any kind of infinity
INFCHARS = re.compile(r'[infINF]')
ESCAPE = re.compile(r'[\x00-\x19\\"\b\f\n\r\t]')
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
ESCAPE_DCT = {
'\\': '\\\\',
'"': '\\"',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
}
for i in range(20):
ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
def floatstr(o, allow_nan=True):
s = str(o)
# If the first non-sign is a digit then it's not a special value
if (o < 0.0 and s[1].isdigit()) or s[0].isdigit():
return s
elif not allow_nan:
raise ValueError("Out of range float values are not JSON compliant: %r"
% (o,))
# These are the string representations on the platforms I've tried
if s == 'nan':
return 'NaN'
if s == 'inf':
return 'Infinity'
if s == '-inf':
return '-Infinity'
# NaN should either be inequal to itself, or equal to everything
if o != o or o == 0.0:
return 'NaN'
# Last ditch effort, assume inf
if o < 0:
return '-Infinity'
return 'Infinity'
def encode_basestring(s):
"""
Return a JSON representation of a Python string
"""
def replace(match):
return ESCAPE_DCT[match.group(0)]
return '"' + ESCAPE.sub(replace, s) + '"'
def encode_basestring_ascii(s):
def replace(match):
s = match.group(0)
try:
return ESCAPE_DCT[s]
except KeyError:
return '\\u%04x' % (ord(s),)
return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
class JSONEncoder(object):
"""
Extensible JSON <http://json.org> encoder for Python data structures.
Supports the following objects and types by default:
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str, unicode | string |
+-------------------+---------------+
| int, long, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
To extend this to recognize other objects, subclass and implement a
``.default()`` method with another method that returns a serializable
object for ``o`` if possible, otherwise it should call the superclass
implementation (to raise ``TypeError``).
"""
__all__ = ['__init__', 'default', 'encode', 'iterencode']
def __init__(self, skipkeys=False, ensure_ascii=True,
check_circular=True, allow_nan=True, sort_keys=False):
"""
Constructor for JSONEncoder, with sensible defaults.
If skipkeys is False, then it is a TypeError to attempt
encoding of keys that are not str, int, long, float or None. If
skipkeys is True, such items are simply skipped.
If ensure_ascii is True, the output is guaranteed to be str
objects with all incoming unicode characters escaped. If
ensure_ascii is false, the output will be unicode object.
If check_circular is True, then lists, dicts, and custom encoded
objects will be checked for circular references during encoding to
prevent an infinite recursion (which would cause an OverflowError).
Otherwise, no such check takes place.
If allow_nan is True, then NaN, Infinity, and -Infinity will be
encoded as such. This behavior is not JSON specification compliant,
but is consistent with most JavaScript based encoders and decoders.
Otherwise, it will be a ValueError to encode such floats.
If sort_keys is True, then the output of dictionaries will be
sorted by key; this is useful for regression tests to ensure
that JSON serializations can be compared on a day-to-day basis.
"""
self.skipkeys = skipkeys
self.ensure_ascii = ensure_ascii
self.check_circular = check_circular
self.allow_nan = allow_nan
self.sort_keys = sort_keys
def _iterencode_list(self, lst, markers=None):
if not lst:
yield '[]'
return
if markers is not None:
markerid = id(lst)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = lst
yield '['
first = True
for value in lst:
if first:
first = False
else:
yield ', '
for chunk in self._iterencode(value, markers):
yield chunk
yield ']'
if markers is not None:
del markers[markerid]
def _iterencode_dict(self, dct, markers=None):
if not dct:
yield '{}'
return
if markers is not None:
markerid = id(dct)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = dct
yield '{'
first = True
if self.ensure_ascii:
encoder = encode_basestring_ascii
else:
encoder = encode_basestring
allow_nan = self.allow_nan
if self.sort_keys:
keys = dct.keys()
keys.sort()
items = [(k,dct[k]) for k in keys]
else:
items = dct.iteritems()
for key, value in items:
if isinstance(key, basestring):
pass
# JavaScript is weakly typed for these, so it makes sense to
# also allow them. Many encoders seem to do something like this.
elif isinstance(key, float):
key = floatstr(key, allow_nan)
elif isinstance(key, (int, long)):
key = str(key)
elif key is True:
key = 'true'
elif key is False:
key = 'false'
elif key is None:
key = 'null'
elif self.skipkeys:
continue
else:
raise TypeError("key %r is not a string" % (key,))
if first:
first = False
else:
yield ', '
yield encoder(key)
yield ': '
for chunk in self._iterencode(value, markers):
yield chunk
yield '}'
if markers is not None:
del markers[markerid]
def _iterencode(self, o, markers=None):
if isinstance(o, basestring):
if self.ensure_ascii:
encoder = encode_basestring_ascii
else:
encoder = encode_basestring
yield encoder(o)
elif o is None:
yield 'null'
elif o is True:
yield 'true'
elif o is False:
yield 'false'
elif isinstance(o, (int, long)):
yield str(o)
elif isinstance(o, float):
yield floatstr(o, self.allow_nan)
elif isinstance(o, (list, tuple)):
for chunk in self._iterencode_list(o, markers):
yield chunk
elif isinstance(o, dict):
for chunk in self._iterencode_dict(o, markers):
yield chunk
else:
if markers is not None:
markerid = id(o)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = o
for chunk in self._iterencode_default(o, markers):
yield chunk
if markers is not None:
del markers[markerid]
def _iterencode_default(self, o, markers=None):
newobj = self.default(o)
return self._iterencode(newobj, markers)
def default(self, o):
"""
Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
return JSONEncoder.default(self, o)
"""
raise TypeError("%r is not JSON serializable" % (o,))
def encode(self, o):
"""
Return a JSON string representation of a Python data structure.
>>> JSONEncoder().encode({"foo": ["bar", "baz"]})
'{"foo":["bar", "baz"]}'
"""
# This doesn't pass the iterator directly to ''.join() because it
# sucks at reporting exceptions. It's going to do this internally
# anyway because it uses PySequence_Fast or similar.
chunks = list(self.iterencode(o))
return ''.join(chunks)
def iterencode(self, o):
"""
Encode the given object and yield each string
representation as available.
For example::
for chunk in JSONEncoder().iterencode(bigobject):
mysocket.write(chunk)
"""
if self.check_circular:
markers = {}
else:
markers = None
return self._iterencode(o, markers)
__all__ = ['JSONEncoder']

View File

@ -0,0 +1,63 @@
"""
Iterator based sre token scanner
"""
import sre_parse, sre_compile, sre_constants
from sre_constants import BRANCH, SUBPATTERN
from sre import VERBOSE, MULTILINE, DOTALL
import re
__all__ = ['Scanner', 'pattern']
FLAGS = (VERBOSE | MULTILINE | DOTALL)
class Scanner(object):
def __init__(self, lexicon, flags=FLAGS):
self.actions = [None]
# combine phrases into a compound pattern
s = sre_parse.Pattern()
s.flags = flags
p = []
for idx, token in enumerate(lexicon):
phrase = token.pattern
try:
subpattern = sre_parse.SubPattern(s,
[(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))])
except sre_constants.error:
raise
p.append(subpattern)
self.actions.append(token)
p = sre_parse.SubPattern(s, [(BRANCH, (None, p))])
self.scanner = sre_compile.compile(p)
def iterscan(self, string, idx=0, context=None):
"""
Yield match, end_idx for each match
"""
match = self.scanner.scanner(string, idx).match
actions = self.actions
lastend = idx
end = len(string)
while True:
m = match()
if m is None:
break
matchbegin, matchend = m.span()
if lastend == matchend:
break
action = actions[m.lastindex]
if action is not None:
rval, next_pos = action(m, context)
if next_pos is not None and next_pos != matchend:
# "fast forward" the scanner
matchend = next_pos
match = self.scanner.scanner(string, matchend).match
yield rval, matchend
lastend = matchend
def pattern(pattern, flags=FLAGS):
def decorator(fn):
fn.pattern = pattern
fn.regex = re.compile(pattern, flags)
return fn
return decorator

View File

@ -28,21 +28,9 @@ def set_language(request):
NullSource = """
/* gettext identity library */
function gettext(msgid) {
return msgid;
}
function ngettext(singular, plural, count) {
if (count == 1) {
return singular;
} else {
return plural;
}
}
function gettext_noop(msgid) {
return msgid;
}
function gettext(msgid) { return msgid; }
function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; }
function gettext_noop(msgid) { return msgid; }
"""
LibHead = """
@ -54,56 +42,47 @@ var catalog = new Array();
LibFoot = """
function gettext(msgid) {
var value = catalog[msgid];
if (typeof(value) == 'undefined') {
return msgid;
} else {
if (typeof(value) == 'string') {
return value;
} else {
return value[0];
}
}
var value = catalog[msgid];
if (typeof(value) == 'undefined') {
return msgid;
} else {
return (typeof(value) == 'string') ? value : value[0];
}
}
function ngettext(singular, plural, count) {
value = catalog[singular];
if (typeof(value) == 'undefined') {
if (count == 1) {
return singular;
} else {
return plural;
}
} else {
return value[pluralidx(count)];
}
value = catalog[singular];
if (typeof(value) == 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value[pluralidx(count)];
}
}
function gettext_noop(msgid) {
return msgid;
}
function gettext_noop(msgid) { return msgid; }
"""
SimplePlural = """
function pluralidx(count) {
if (count == 1) {
return 0;
} else {
return 1;
}
}
function pluralidx(count) { return (count == 1) ? 0 : 1; }
"""
InterPolate = r"""
function interpolate(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/, function(match){return String(obj.shift())});
}
if (named) {
return fmt.replace(/%\(\w+\)s/, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/, function(match){return String(obj.shift())});
}
}
"""
def null_javascript_catalog(request, domain=None, packages=None):
"""
Returns "identity" versions of the JavaScript i18n functions -- i.e.,
versions that don't actually do anything.
"""
return http.HttpResponse(NullSource + InterPolate, 'text/javascript')
def javascript_catalog(request, domain='djangojs', packages=None):
"""
Returns the selected language catalog as a javascript library.
@ -191,4 +170,3 @@ def javascript_catalog(request, domain='djangojs', packages=None):
src.append(InterPolate)
src = ''.join(src)
return http.HttpResponse(src, 'text/javascript')

View File

@ -128,6 +128,8 @@ A collection of template filters that implement these common markup languages:
* Markdown
* ReST (ReStructured Text)
For documentation, read the source code in django/contrib/markup/templatetags/markup.py.
redirects
=========

View File

@ -267,25 +267,54 @@ previous section). You can tell them apart with ``is_anonymous()``, like so::
How to log a user in
--------------------
Depending on your task, you'll probably want to make sure to validate the
user's username and password before you log them in. The easiest way to do so
is to use the built-in ``authenticate`` and ``login`` functions from within a
view::
Django provides two functions in ``django.contrib.auth``: ``authenticate()``
and ``login()``.
To authenticate a given username and password, use ``authenticate()``. It
takes two keyword arguments, ``username`` and ``password``, and it returns
a ``User`` object if the password is valid for the given username. If the
password is invalid, ``authenticate()`` returns ``None``. Example::
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
print "You provided a correct username and password!"
else:
print "Your username and password were incorrect."
To log a user in, in a view, use ``login()``. It takes an ``HttpRequest``
object and a ``User`` object. ``login()`` saves the user's ID in the session,
using Django's session framework, so, as mentioned above, you'll need to make
sure to have the session middleware installed.
This example shows how you might use both ``authenticate()`` and ``login()``::
from django.contrib.auth import authenticate, login
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
``authenticate`` checks the username and password. If they are valid it
returns a user object, otherwise it returns ``None``. ``login`` makes it so
your users don't have send a username and password for every request. Because
the ``login`` function uses sessions, you'll need to make sure you have
``SessionMiddleware`` enabled. See the `session documentation`_ for
more information.
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
else:
# Return an error message.
How to log a user out
---------------------
To log out a user who has been logged in via ``django.contrib.auth.login()``,
use ``django.contrib.auth.logout()`` within your view. It takes an
``HttpRequest`` object and has no return value. Example::
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
Note that ``logout()`` doesn't throw any errors if the user wasn't logged in.
Limiting access to logged-in users
----------------------------------
@ -568,7 +597,7 @@ The currently logged-in user and his/her permissions are made available in the
setting contains ``"django.core.context_processors.auth"``, which is default.
For more, see the `RequestContext docs`_.
.. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-djangocontext
.. _RequestContext docs: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-requestcontext
Users
-----
@ -681,61 +710,93 @@ database. To send messages to anonymous users, use the `session framework`_.
.. _session framework: http://www.djangoproject.com/documentation/sessions/
Other Authentication Sources
Other authentication sources
============================
Django supports other authentication sources as well. You can even use
multiple sources at the same time.
The authentication that comes with Django is good enough for most common cases,
but you may have the need to hook into another authentication source -- that
is, another source of usernames and passwords or authentication methods.
Using multiple backends
-----------------------
For example, your company may already have an LDAP setup that stores a username
and password for every employee. It'd be a hassle for both the network
administrator and the users themselves if users had separate accounts in LDAP
and the Django-based applications.
The list of backends to use is controlled by the ``AUTHENTICATION_BACKENDS``
setting. This should be a tuple of python path names. It defaults to
``('django.contrib.auth.backends.ModelBackend',)``. To add additional backends
just add them to your settings.py file. Ordering matters, so if the same
username and password is valid in multiple backends, the first one in the
list will return a user object, and the remaining ones won't even get a chance.
So, to handle situations like this, the Django authentication system lets you
plug in another authentication sources. You can override Django's default
database-based scheme, or you can use the default system in tandem with other
systems.
Specifying authentication backends
----------------------------------
Behind the scenes, Django maintains a list of "authentication backends" that it
checks for authentication. When somebody calls
``django.contrib.auth.authenticate()`` -- as described in "How to log a user in"
above -- Django tries authenticating across all of its authentication backends.
If the first authentication method fails, Django tries the second one, and so
on, until all backends have been attempted.
The list of authentication backends to use is specified in the
``AUTHENTICATION_BACKENDS`` setting. This should be a tuple of Python path
names that point to Python classes that know how to authenticate. These classes
can be anywhere on your Python path.
By default, ``AUTHENTICATION_BACKENDS`` is set to::
('django.contrib.auth.backends.ModelBackend',)
That's the basic authentication scheme that checks the Django users database.
The order of ``AUTHENTICATION_BACKENDS`` matters, so if the same username and
password is valid in multiple backends, Django will stop processing at the
first positive match.
Writing an authentication backend
---------------------------------
An authentication backend is a class that implements 2 methods:
``get_user(id)`` and ``authenticate(**credentials)``. The ``get_user`` method
takes an id, which could be a username, and database id, whatever, and returns
a user object. The ``authenticate`` method takes credentials as keyword
arguments. Many times it will just look like this::
An authentication backend is a class that implements two methods:
``get_user(id)`` and ``authenticate(**credentials)``.
The ``get_user`` method takes an ``id`` -- which could be a username, database
ID or whatever -- and returns a ``User`` object.
The ``authenticate`` method takes credentials as keyword arguments. Most of
the time, it'll just look like this::
class MyBackend:
def authenticate(username=None, password=None):
# check the username/password and return a user
# Check the username/password and return a User.
but it could also authenticate a token like so::
But it could also authenticate a token, like so::
class MyBackend:
def authenticate(token=None):
# check the token and return a user
# Check the token and return a User.
Regardless, ``authenticate`` should check the credentials it gets, and if they
are valid, it should return a user object that matches those credentials.
Either way, ``authenticate`` should check the credentials it gets, and it
should return a ``User`` object that matches those credentials, if the
credentials are valid. If they're not valid, it should return ``None``.
The Django admin system is tightly coupled to the Django User object described
at the beginning of this document. For now, the best way to deal with this is
to create a Django User object for each user that exists for your backend
(i.e. in your LDAP directory, your external SQL database, etc.) You can either
write a script to do this in advance, or your ``authenticate`` method can do
it the first time a user logs in. Here's an example backend that
authenticates against a username and password variable defined in your
``settings.py`` file and creates a Django user object the first time they
authenticate::
The Django admin system is tightly coupled to the Django ``User`` object
described at the beginning of this document. For now, the best way to deal with
this is to create a Django ``User`` object for each user that exists for your
backend (e.g., in your LDAP directory, your external SQL database, etc.) You
can either write a script to do this in advance, or your ``authenticate``
method can do it the first time a user logs in.
Here's an example backend that authenticates against a username and password
variable defined in your ``settings.py`` file and creates a Django ``User``
object the first time a user authenticates::
from django.conf import settings
from django.contrib.auth.models import User, check_password
class SettingsBackend:
"""
Authenticate against vars in settings.py Use the login name, and a hash
of the password. For example:
Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
Use the login name, and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
@ -747,8 +808,9 @@ authenticate::
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. Note that we can set password to anything
# as it won't be checked, the password from settings.py will.
# Create a new user. Note that we can set password
# to anything, because it won't be checked; the password
# from settings.py will.
user = User(username=username, password='get from settings.py')
user.is_staff = True
user.is_superuser = True

View File

@ -411,6 +411,36 @@ Using a ``FileField`` or an ``ImageField`` in a model takes a few steps:
absolute URL to your image in a template with
``{{ object.get_mug_shot_url }}``.
Databases and models
====================
How can I see the raw SQL queries Django is running?
----------------------------------------------------
Make sure your Django ``DEBUG`` setting is set to ``True``. Then, just do
this::
>>> from django.db import connection
>>> connection.queries
[{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls',
'time': '0.002'}]
``connection.queries`` is only available if ``DEBUG`` is ``True``. It's a list
of dictionaries in order of query execution. Each dictionary has the following::
``sql`` -- The raw SQL statement
``time`` -- How long the statement took to execute, in seconds.
``connection.queries`` includes all SQL statements -- INSERTs, UPDATES,
SELECTs, etc. Each time your app hits the database, the query will be recorded.
Can I use Django with a pre-existing database?
----------------------------------------------
Yes. See `Integrating with a legacy database`_.
.. _`Integrating with a legacy database`: http://www.djangoproject.com/documentation/legacy_databases/
If I make changes to a model, how do I update the database?
-----------------------------------------------------------
@ -439,35 +469,24 @@ uniqueness at that level. Single-column primary keys are needed for things such
as the admin interface to work; e.g., you need a simple way of being able to
specify an object to edit or delete.
The database API
================
How do I add database-specific options to my CREATE TABLE statements, such as specifying MyISAM as the table type?
------------------------------------------------------------------------------------------------------------------
How can I see the raw SQL queries Django is running?
----------------------------------------------------
We try to avoid adding special cases in the Django code to accomodate all the
database-specific options such as table type, etc. If you'd like to use any of
these options, create an `SQL initial data file`_ that contains ``ALTER TABLE``
statements that do what you want to do. The initial data files are executed in
your database after the ``CREATE TABLE`` statements.
Make sure your Django ``DEBUG`` setting is set to ``True``. Then, just do
this::
For example, if you're using MySQL and want your tables to use the MyISAM table
type, create an initial data file and put something like this in it::
>>> from django.db import connection
>>> connection.queries
[{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls',
'time': '0.002'}]
ALTER TABLE myapp_mytable ENGINE=MyISAM;
``connection.queries`` is only available if ``DEBUG`` is ``True``. It's a list
of dictionaries in order of query execution. Each dictionary has the following::
As explained in the `SQL initial data file`_ documentation, this SQL file can
contain arbitrary SQL, so you can make any sorts of changes you need to make.
``sql`` -- The raw SQL statement
``time`` -- How long the statement took to execute, in seconds.
``connection.queries`` includes all SQL statements -- INSERTs, UPDATES,
SELECTs, etc. Each time your app hits the database, the query will be recorded.
Can I use Django with a pre-existing database?
----------------------------------------------
Yes. See `Integrating with a legacy database`_.
.. _`Integrating with a legacy database`: http://www.djangoproject.com/documentation/legacy_databases/
.. _SQL initial data file: http://www.djangoproject.com/documentation/model_api/#providing-initial-sql-data
Why is Django leaking memory?
-----------------------------

View File

@ -35,12 +35,25 @@ How to internationalize your app: in three steps
support.
3. Activate the locale middleware in your Django settings.
.. admonition:: Behind the scenes
Django's translation machinery uses the standard ``gettext`` module that
comes with Python.
If you don't need internationalization
======================================
Django's internationalization hooks are on by default, and that means there's a
bit of i18n-related overhead in certain places of the framework. If you don't
use internationalization, you should take the two seconds to set
``USE_I18N = False`` in your settings file. If ``USE_I18N`` is set to
``False``, then Django will make some optimizations so as not to load the
internationalization machinery.
See the `documentation for USE_I18N`_.
.. _documentation for USE_I18N: http://www.djangoproject.com/documentation/settings/#use-i18n
How to specify translation strings
==================================

View File

@ -78,8 +78,25 @@ The Django object itself can be inspected as ``deserialized_object.object``.
Serialization formats
---------------------
Django "ships" with a few included serializers, and there's a simple API for creating and registering your own...
Django "ships" with a few included serializers:
.. note::
========== ==============================================================
Identifier Information
========== ==============================================================
``xml`` Serializes to and from a simple XML dialect.
... which will be documented once the API is stable :)
``json`` Serializes to and from JSON_ (using a version of simplejson_
bundled with Django).
``python`` Translates to and from "simple" Python objects (lists, dicts,
strings, etc.). Not really all that useful on its own, but
used as a base for other serializers.
========== ==============================================================
.. _json: http://json.org/
.. _simplejson: http://undefined.org/python/#simplejson
Writing custom serializers
``````````````````````````
XXX ...

View File

@ -107,15 +107,20 @@ For more, see the `diffsettings documentation`_.
Using settings in Python code
=============================
In your Django apps, use settings by importing them from
In your Django apps, use settings by importing the object
``django.conf.settings``. Example::
from django.conf.settings import DEBUG
from django.conf import settings
if DEBUG:
if settings.DEBUG:
# Do something
Note that your code should *not* import from either ``global_settings`` or
Note that ``django.conf.settings`` isn't a module -- it's an object. So
importing individual settings is not possible::
from django.conf.settings import DEBUG # This won't work.
Also note that your code should *not* import from either ``global_settings`` or
your own settings file. ``django.conf.settings`` abstracts the concepts of
default settings and site-specific settings; it presents a single interface.
It also decouples the code that uses settings from the location of your
@ -127,9 +132,9 @@ Altering settings at runtime
You shouldn't alter settings in your applications at runtime. For example,
don't do this in a view::
from django.conf.settings import DEBUG
from django.conf import settings
DEBUG = True # Don't do this!
settings.DEBUG = True # Don't do this!
The only place you should assign to settings is in a settings file.
@ -738,6 +743,16 @@ A boolean that specifies whether to output the "Etag" header. This saves
bandwidth but slows down performance. This is only used if ``CommonMiddleware``
is installed (see the `middleware docs`_).
USE_I18N
--------
Default: ``True``
A boolean that specifies whether Django's internationalization system should be
enabled. This provides an easy way to turn it off, for performance. If this is
set to ``False, Django will make some optimizations so as not to load the
internationalization machinery.
YEAR_MONTH_FORMAT
-----------------

View File

@ -75,6 +75,10 @@ API_TESTS = """
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__pk=1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications=1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications=p1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__title__startswith="Science")
[<Article: NASA uses Python>, <Article: NASA uses Python>]
@ -89,6 +93,13 @@ API_TESTS = """
>>> Article.objects.filter(publications__title__startswith="Science").distinct().count()
1
>>> Article.objects.filter(publications__in=[1,2]).distinct()
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__in=[1,p2]).distinct()
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__in=[p1,p2]).distinct()
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
# Reverse m2m queries are supported (i.e., starting at the table that doesn't
# have a ManyToManyField).
>>> Publication.objects.filter(id__exact=1)
@ -101,9 +112,19 @@ API_TESTS = """
>>> Publication.objects.filter(article__id__exact=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article__pk=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article=a1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article__in=[1,2]).distinct()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]
>>> Publication.objects.filter(article__in=[1,a2]).distinct()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]
>>> Publication.objects.filter(article__in=[a1,a2]).distinct()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]
# If we delete a Publication, its Articles won't be able to access it.
>>> p1.delete()

View File

@ -136,6 +136,10 @@ False
>>> Article.objects.filter(reporter__first_name__exact='John')
[<Article: John's second story>, <Article: This is a test>]
# Check that implied __exact also works
>>> Article.objects.filter(reporter__first_name='John')
[<Article: John's second story>, <Article: This is a test>]
# Query twice over the related field.
>>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
[<Article: John's second story>, <Article: This is a test>]
@ -151,10 +155,20 @@ False
[<Article: John's second story>, <Article: This is a test>]
# Find all Articles for the Reporter whose ID is 1.
# Use direct ID check, pk check, and object comparison
>>> Article.objects.filter(reporter__id__exact=1)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter__pk=1)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter=1)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter=r)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter__in=[1,2]).distinct()
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
>>> Article.objects.filter(reporter__in=[r,r2]).distinct()
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
# You need two underscores between "reporter" and "id" -- not one.
>>> Article.objects.filter(reporter_id__exact=1)
@ -168,10 +182,6 @@ Traceback (most recent call last):
...
TypeError: Cannot resolve keyword 'reporter_id' into field
# "pk" shortcut syntax works in a related context, too.
>>> Article.objects.filter(reporter__pk=1)
[<Article: John's second story>, <Article: This is a test>]
# You can also instantiate an Article by passing
# the Reporter's ID instead of a Reporter object.
>>> a3 = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter_id=r.id)
@ -200,6 +210,18 @@ TypeError: Cannot resolve keyword 'reporter_id' into field
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__pk=1)
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article=1)
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article=a)
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__in=[1,4]).distinct()
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__in=[1,a3]).distinct()
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__in=[a,a3]).distinct()
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__headline__startswith='This')
[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
>>> Reporter.objects.filter(article__headline__startswith='This').distinct()
@ -216,6 +238,12 @@ TypeError: Cannot resolve keyword 'reporter_id' into field
[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
>>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__reporter__exact=r).distinct()
[<Reporter: John Smith>]
# Check that implied __exact also works
>>> Reporter.objects.filter(article__reporter=r).distinct()
[<Reporter: John Smith>]
# If you delete a reporter, his articles will be deleted.
>>> Article.objects.all()

View File

@ -94,6 +94,12 @@ DoesNotExist: Restaurant matching query does not exist.
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place__exact=1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place__exact=p1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place=1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place=p1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place__pk=1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place__name__startswith="Demon")
@ -105,8 +111,18 @@ DoesNotExist: Restaurant matching query does not exist.
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__place__exact=1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__place__exact=p1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__pk=1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant=1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant=r)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__exact=1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__exact=r)
<Place: Demon Dogs the place>
# Add a Waiter to the Restaurant.
>>> w = r.waiter_set.create(name='Joe')
@ -115,14 +131,22 @@ DoesNotExist: Restaurant matching query does not exist.
<Waiter: Joe the waiter at Demon Dogs the restaurant>
# Query the waiters
>>> Waiter.objects.filter(restaurant__place__pk=1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant__place__exact=1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant__place__exact=p1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant__pk=1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(id__exact=1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(pk=1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant=1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant=r)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)

View File

@ -91,4 +91,31 @@ API_TESTS = """
>>> Article.objects.all()
[<Article: Poker has no place on television>, <Article: Time to reform copyright>]
# Django also ships with a built-in JSON serializers
>>> json = serializers.serialize("json", Category.objects.filter(pk=2))
>>> json
'[{"pk": "2", "model": "serializers.category", "fields": {"name": "Music"}}]'
# You can easily create new objects by deserializing data with an empty PK
# (It's easier to demo this with JSON...)
>>> new_author_json = '[{"pk": null, "model": "serializers.author", "fields": {"name": "Bill"}}]'
>>> for obj in serializers.deserialize("json", new_author_json):
... obj.save()
>>> Author.objects.all()
[<Author: Bill>, <Author: Jane>, <Author: Joe>]
# All the serializers work the same
>>> json = serializers.serialize("json", Article.objects.all())
>>> for obj in serializers.deserialize("json", json):
... print obj
<DeserializedObject: Poker has no place on television>
<DeserializedObject: Time to reform copyright>
>>> json = json.replace("Poker has no place on television", "Just kidding; I love TV poker")
>>> for obj in serializers.deserialize("json", json):
... obj.save()
>>> Article.objects.all()
[<Article: Just kidding; I love TV poker>, <Article: Time to reform copyright>]
"""