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.db.models import signals
from django.db.models.fields import FieldDoesNotExist
@ -42,12 +42,18 @@ class Manager(object):
# PROXIES TO QUERYSET #
#######################
def get_empty_query_set(self):
return EmptyQuerySet(self.model)
def get_query_set(self):
"""Returns a new QuerySet object. Subclasses can override this method
to easily customise the behaviour of the Manager.
"""
return QuerySet(self.model)
def none(self):
return self.get_empty_query_set()
def all(self):
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.
GET_ITERATOR_CHUNK_SIZE = 100
class EmptyResultSet(Exception):
pass
####################
# HELPER FUNCTIONS #
####################
@ -168,7 +171,12 @@ class QuerySet(object):
extra_select = self._select.items()
cursor = connection.cursor()
try:
select, sql, params = self._get_sql_clause()
except EmptyResultSet:
raise StopIteration
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
fill_cache = self._select_related
index_end = len(self.model._meta.fields)
@ -192,7 +200,12 @@ class QuerySet(object):
counter._offset = None
counter._limit = None
counter._select_related = False
try:
select, sql, params = counter._get_sql_clause()
except EmptyResultSet:
return 0
cursor = connection.cursor()
if self._distinct:
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]
cursor = connection.cursor()
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]
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
while 1:
@ -545,7 +563,12 @@ class DateQuerySet(QuerySet):
if self._field.null:
self._where.append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
try:
select, sql, params = self._get_sql_clause()
except EmptyResultSet:
raise StopIteration
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.quote_name(self._field.column))), sql, self._order)
@ -563,6 +586,25 @@ class DateQuerySet(QuerySet):
c._order = self._order
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):
"Base class for QAnd and QOr"
def __init__(self, *args):
@ -571,10 +613,14 @@ class QOperator(object):
def get_sql(self, opts):
joins, where, params = SortedDict(), [], []
for val in self.args:
try:
joins2, where2, params2 = val.get_sql(opts)
joins.update(joins2)
where.extend(where2)
params.extend(params2)
except EmptyResultSet:
if not isinstance(self, QOr):
raise EmptyResultSet
if where:
return joins, ['(%s)' % self.operator.join(where)], params
return joins, [], params
@ -628,8 +674,11 @@ class QNot(Q):
self.q = q
def get_sql(self, opts):
try:
joins, where, params = self.q.get_sql(opts)
where2 = ['(NOT (%s))' % " AND ".join(where)]
except EmptyResultSet:
return SortedDict(), [], []
return joins, where2, params
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:
return '%s%s IN (%s)' % (table_prefix, field_name, in_string)
else:
# Most backends do not accept an empty string inside the IN
# 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'
raise EmptyResultSet
elif lookup_type == 'range':
return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name)
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"
def __init__(self, field_name, is_required=False, validator_list=None):
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)
def render(self, data):

View File

@ -526,6 +526,21 @@ Examples::
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[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()``
~~~~~~~~~~~~~~~~~~~~

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.
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
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``.
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
------------------

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]
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
Note that we no longer need to import ``loader``, ``Context`` or
``HttpResponse``.
Note that once we've done this in all these views, we no longer need to import ``loader``, ``Context`` and ``HttpResponse``.
The ``render_to_response()`` function takes a template name as its first
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()``
--------------------------------------
**New in the Django development version.**
**New in Django development version.**
Similarly, you can pass extra options to ``include()``. When you pass extra
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
===========================================
**New in the Django development version.**
**New in Django development version.**
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

View File

@ -191,4 +191,19 @@ DoesNotExist: Article matching query does not exist.
>>> Article.objects.filter(headline__contains='\\')
[<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>]
"""}