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

newforms-admin: Merged to [4399]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4400 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-01-23 04:31:02 +00:00
parent 8c4c07b5d0
commit a670fccf79
10 changed files with 133 additions and 45 deletions

View File

@ -1,4 +1,4 @@
from django.db.models.query import QuerySet from django.db.models.query import QuerySet, EmptyQuerySet
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.db.models import signals from django.db.models import signals
from django.db.models.fields import FieldDoesNotExist from django.db.models.fields import FieldDoesNotExist
@ -41,12 +41,18 @@ class Manager(object):
####################### #######################
# PROXIES TO QUERYSET # # PROXIES TO QUERYSET #
####################### #######################
def get_empty_query_set(self):
return EmptyQuerySet(self.model)
def get_query_set(self): def get_query_set(self):
"""Returns a new QuerySet object. Subclasses can override this method """Returns a new QuerySet object. Subclasses can override this method
to easily customise the behaviour of the Manager. to easily customise the behaviour of the Manager.
""" """
return QuerySet(self.model) return QuerySet(self.model)
def none(self):
return self.get_empty_query_set()
def all(self): def all(self):
return self.get_query_set() return self.get_query_set()

View File

@ -25,6 +25,9 @@ QUERY_TERMS = (
# Larger values are slightly faster at the expense of more storage space. # Larger values are slightly faster at the expense of more storage space.
GET_ITERATOR_CHUNK_SIZE = 100 GET_ITERATOR_CHUNK_SIZE = 100
class EmptyResultSet(Exception):
pass
#################### ####################
# HELPER FUNCTIONS # # HELPER FUNCTIONS #
#################### ####################
@ -168,7 +171,12 @@ class QuerySet(object):
extra_select = self._select.items() extra_select = self._select.items()
cursor = connection.cursor() cursor = connection.cursor()
select, sql, params = self._get_sql_clause()
try:
select, sql, params = self._get_sql_clause()
except EmptyResultSet:
raise StopIteration
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
fill_cache = self._select_related fill_cache = self._select_related
index_end = len(self.model._meta.fields) index_end = len(self.model._meta.fields)
@ -192,7 +200,12 @@ class QuerySet(object):
counter._offset = None counter._offset = None
counter._limit = None counter._limit = None
counter._select_related = False counter._select_related = False
select, sql, params = counter._get_sql_clause()
try:
select, sql, params = counter._get_sql_clause()
except EmptyResultSet:
return 0
cursor = connection.cursor() cursor = connection.cursor()
if self._distinct: if self._distinct:
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
@ -523,7 +536,12 @@ class ValuesQuerySet(QuerySet):
field_names = [f.attname for f in self.model._meta.fields] field_names = [f.attname for f in self.model._meta.fields]
cursor = connection.cursor() cursor = connection.cursor()
select, sql, params = self._get_sql_clause()
try:
select, sql, params = self._get_sql_clause()
except EmptyResultSet:
raise StopIteration
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
while 1: while 1:
@ -545,7 +563,12 @@ class DateQuerySet(QuerySet):
if self._field.null: if self._field.null:
self._where.append('%s.%s IS NOT NULL' % \ self._where.append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column))) (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
select, sql, params = self._get_sql_clause()
try:
select, sql, params = self._get_sql_clause()
except EmptyResultSet:
raise StopIteration
sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \ sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
(backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table), (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
backend.quote_name(self._field.column))), sql, self._order) backend.quote_name(self._field.column))), sql, self._order)
@ -562,6 +585,25 @@ class DateQuerySet(QuerySet):
c._kind = self._kind c._kind = self._kind
c._order = self._order c._order = self._order
return c return c
class EmptyQuerySet(QuerySet):
def __init__(self, model=None):
super(EmptyQuerySet, self).__init__(model)
self._result_cache = []
def iterator(self):
raise StopIteration
def count(self):
return 0
def delete(self):
pass
def _clone(self, klass=None, **kwargs):
c = super(EmptyQuerySet, self)._clone(klass, **kwargs)
c._result_cache = []
return c
class QOperator(object): class QOperator(object):
"Base class for QAnd and QOr" "Base class for QAnd and QOr"
@ -571,10 +613,14 @@ class QOperator(object):
def get_sql(self, opts): def get_sql(self, opts):
joins, where, params = SortedDict(), [], [] joins, where, params = SortedDict(), [], []
for val in self.args: for val in self.args:
joins2, where2, params2 = val.get_sql(opts) try:
joins.update(joins2) joins2, where2, params2 = val.get_sql(opts)
where.extend(where2) joins.update(joins2)
params.extend(params2) where.extend(where2)
params.extend(params2)
except EmptyResultSet:
if not isinstance(self, QOr):
raise EmptyResultSet
if where: if where:
return joins, ['(%s)' % self.operator.join(where)], params return joins, ['(%s)' % self.operator.join(where)], params
return joins, [], params return joins, [], params
@ -628,8 +674,11 @@ class QNot(Q):
self.q = q self.q = q
def get_sql(self, opts): def get_sql(self, opts):
joins, where, params = self.q.get_sql(opts) try:
where2 = ['(NOT (%s))' % " AND ".join(where)] joins, where, params = self.q.get_sql(opts)
where2 = ['(NOT (%s))' % " AND ".join(where)]
except EmptyResultSet:
return SortedDict(), [], []
return joins, where2, params return joins, where2, params
def get_where_clause(lookup_type, table_prefix, field_name, value): def get_where_clause(lookup_type, table_prefix, field_name, value):
@ -645,11 +694,7 @@ def get_where_clause(lookup_type, table_prefix, field_name, value):
if in_string: if in_string:
return '%s%s IN (%s)' % (table_prefix, field_name, in_string) return '%s%s IN (%s)' % (table_prefix, field_name, in_string)
else: else:
# Most backends do not accept an empty string inside the IN raise EmptyResultSet
# expression, i.e. cannot do "WHERE ... IN ()". Since there are
# also some backends that do not accept "WHERE false", we instead
# use an expression that always evaluates to False.
return '0=1'
elif lookup_type == 'range': elif lookup_type == 'range':
return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name) return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name)
elif lookup_type in ('year', 'month', 'day'): elif lookup_type in ('year', 'month', 'day'):

View File

@ -569,7 +569,7 @@ class NullBooleanField(SelectField):
"This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None" "This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None"
def __init__(self, field_name, is_required=False, validator_list=None): def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = [] if validator_list is None: validator_list = []
SelectField.__init__(self, field_name, choices=[('1', 'Unknown'), ('2', 'Yes'), ('3', 'No')], SelectField.__init__(self, field_name, choices=[('1', _('Unknown')), ('2', _('Yes')), ('3', _('No'))],
is_required=is_required, validator_list=validator_list) is_required=is_required, validator_list=validator_list)
def render(self, data): def render(self, data):

View File

@ -525,6 +525,21 @@ Examples::
[datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)] [datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day') >>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.datetime(2005, 3, 20)] [datetime.datetime(2005, 3, 20)]
``none()``
~~~~~~~~~~
**New in Django development version**
Returns an ``EmptyQuerySet`` -- a ``QuerySet`` that always evaluates to
an empty list. This can be used in cases where you know that you should
return an empty result set and your caller is expecting a ``QuerySet``
object (instead of returning an empty list, for example.)
Examples::
>>> Entry.objects.none()
[]
``select_related()`` ``select_related()``
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~

View File

@ -99,7 +99,7 @@ which is a dictionary of the parameters captured in the URL.
dictionary is callable, the generic view will call it dictionary is callable, the generic view will call it
just before rendering the template. (**This is new in the just before rendering the template. (**This is new in the
Django development version.**) Django development version.**)
**Example:** **Example:**
Given the following URL patterns:: Given the following URL patterns::
@ -205,11 +205,11 @@ If ``template_name`` isn't specified, this view will use the template
``<app_label>/<model_name>_archive.html`` by default, where: ``<app_label>/<model_name>_archive.html`` by default, where:
* ``<model_name>`` is your model's name in all lowercase. For a model * ``<model_name>`` is your model's name in all lowercase. For a model
``StaffMember``, that'd be ``staffmember``. ``StaffMember``, that'd be ``staffmember``.
* ``<app_label>`` is the right-most part of the full Python path to * ``<app_label>`` is the right-most part of the full Python path to
your model's app. For example, if your model lives in your model's app. For example, if your model lives in
``apps/blog/models.py``, that'd be ``blog``. ``apps/blog/models.py``, that'd be ``blog``.
**Template context:** **Template context:**
@ -266,9 +266,9 @@ to ``True``.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. The to use in the template context. By default, this is ``'object'``. The
view will append ``'_list'`` to the value of this parameter in view will append ``'_list'`` to the value of this parameter in
determining the variable's name. determining the variable's name.
* ``make_object_list``: A boolean specifying whether to retrieve the full * ``make_object_list``: A boolean specifying whether to retrieve the full
list of objects for this year and pass those to the template. If ``True``, list of objects for this year and pass those to the template. If ``True``,
@ -360,9 +360,9 @@ date in the *future* are not displayed unless you set ``allow_future`` to
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. The to use in the template context. By default, this is ``'object'``. The
view will append ``'_list'`` to the value of this parameter in view will append ``'_list'`` to the value of this parameter in
determining the variable's name. determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting. to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@ -441,9 +441,9 @@ in the *future* are not displayed unless you set ``allow_future`` to ``True``.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. The to use in the template context. By default, this is ``'object'``. The
view will append ``'_list'`` to the value of this parameter in view will append ``'_list'`` to the value of this parameter in
determining the variable's name. determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting. to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@ -526,9 +526,9 @@ you set ``allow_future`` to ``True``.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. The to use in the template context. By default, this is ``'object'``. The
view will append ``'_list'`` to the value of this parameter in view will append ``'_list'`` to the value of this parameter in
determining the variable's name. determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting. to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@ -638,7 +638,7 @@ future, the view will throw a 404 error by default, unless you set
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. to use in the template context. By default, this is ``'object'``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting. to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@ -710,9 +710,9 @@ A page representing a list of objects.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. The to use in the template context. By default, this is ``'object'``. The
view will append ``'_list'`` to the value of this parameter in view will append ``'_list'`` to the value of this parameter in
determining the variable's name. determining the variable's name.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting. to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@ -824,7 +824,7 @@ A page representing an individual object.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. to use in the template context. By default, this is ``'object'``.
* ``mimetype``: The MIME type to use for the resulting document. Defaults * ``mimetype``: The MIME type to use for the resulting document. Defaults
to the value of the ``DEFAULT_CONTENT_TYPE`` setting. to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@ -973,7 +973,7 @@ object. This uses the automatic manipulators that come with Django models.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. to use in the template context. By default, this is ``'object'``.
**Template name:** **Template name:**
@ -1054,7 +1054,7 @@ contain a form that POSTs to the same URL.
the view's template. See the `RequestContext docs`_. the view's template. See the `RequestContext docs`_.
* ``template_object_name``: Designates the name of the template variable * ``template_object_name``: Designates the name of the template variable
to use in the template context. By default, this is ``'object'``. to use in the template context. By default, this is ``'object'``.
**Template name:** **Template name:**

View File

@ -1408,7 +1408,10 @@ This should be set to a list of field names that will be searched whenever
somebody submits a search query in that text box. somebody submits a search query in that text box.
These fields should be some kind of text field, such as ``CharField`` or These fields should be some kind of text field, such as ``CharField`` or
``TextField``. ``TextField``. You can also perform a related lookup on a ``ForeignKey`` with
the lookup API "follow" notation::
search_fields = ['foreign_key__related_fieldname']
When somebody does a search in the admin search box, Django splits the search When somebody does a search in the admin search box, Django splits the search
query into words and returns all objects that contain each of the words, case query into words and returns all objects that contain each of the words, case

View File

@ -557,6 +557,11 @@ Default: ``''`` (Empty string)
URL that handles the media served from ``MEDIA_ROOT``. URL that handles the media served from ``MEDIA_ROOT``.
Example: ``"http://media.lawrence.com"`` Example: ``"http://media.lawrence.com"``
Note that this should have a trailing slash if it has a path component.
Good: ``"http://www.example.com/static/"``
Bad: ``"http://www.example.com/static"``
MIDDLEWARE_CLASSES MIDDLEWARE_CLASSES
------------------ ------------------

View File

@ -260,8 +260,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list}) return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
Note that we no longer need to import ``loader``, ``Context`` or Note that once we've done this in all these views, we no longer need to import ``loader``, ``Context`` and ``HttpResponse``.
``HttpResponse``.
The ``render_to_response()`` function takes a template name as its first The ``render_to_response()`` function takes a template name as its first
argument and a dictionary as its optional second argument. It returns an argument and a dictionary as its optional second argument. It returns an

View File

@ -393,7 +393,7 @@ to pass metadata and options to views.
Passing extra options to ``include()`` Passing extra options to ``include()``
-------------------------------------- --------------------------------------
**New in the Django development version.** **New in Django development version.**
Similarly, you can pass extra options to ``include()``. When you pass extra Similarly, you can pass extra options to ``include()``. When you pass extra
options to ``include()``, *each* line in the included URLconf will be passed options to ``include()``, *each* line in the included URLconf will be passed
@ -435,7 +435,7 @@ every view in the the included URLconf accepts the extra options you're passing.
Passing callable objects instead of strings Passing callable objects instead of strings
=========================================== ===========================================
**New in the Django development version.** **New in Django development version.**
Some developers find it more natural to pass the actual Python function object Some developers find it more natural to pass the actual Python function object
rather than a string containing the path to its module. This alternative is rather than a string containing the path to its module. This alternative is

View File

@ -191,4 +191,19 @@ DoesNotExist: Article matching query does not exist.
>>> Article.objects.filter(headline__contains='\\') >>> Article.objects.filter(headline__contains='\\')
[<Article: Article with \ backslash>] [<Article: Article with \ backslash>]
# none() returns an EmptyQuerySet that behaves like any other QuerySet object
>>> Article.objects.none()
[]
>>> Article.objects.none().filter(headline__startswith='Article')
[]
>>> Article.objects.none().count()
0
# using __in with an empty list should return an empty query set
>>> Article.objects.filter(id__in=[])
[]
>>> Article.objects.exclude(id__in=[])
[<Article: Article with \ backslash>, <Article: Article% with percent sign>, <Article: Article_ with underscore>, <Article: Article 5>, <Article: Article 6>, <Article: Article 4>, <Article: Article 2>, <Article: Article 3>, <Article: Article 7>, <Article: Article 1>]
"""} """}