Author: adrian
Date: 2007-01-22 22:31:02 -0600 (Mon, 22 Jan 2007)
New Revision: 4400

Modified:
   django/branches/newforms-admin/django/db/models/manager.py
   django/branches/newforms-admin/django/db/models/query.py
   django/branches/newforms-admin/django/oldforms/__init__.py
   django/branches/newforms-admin/docs/db-api.txt
   django/branches/newforms-admin/docs/generic_views.txt
   django/branches/newforms-admin/docs/model-api.txt
   django/branches/newforms-admin/docs/settings.txt
   django/branches/newforms-admin/docs/tutorial03.txt
   django/branches/newforms-admin/docs/url_dispatch.txt
   django/branches/newforms-admin/tests/modeltests/lookup/models.py
Log:
newforms-admin: Merged to [4399]

Modified: django/branches/newforms-admin/django/db/models/manager.py
===================================================================
--- django/branches/newforms-admin/django/db/models/manager.py  2007-01-23 
02:30:55 UTC (rev 4399)
+++ django/branches/newforms-admin/django/db/models/manager.py  2007-01-23 
04:31:02 UTC (rev 4400)
@@ -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
@@ -41,12 +41,18 @@
     #######################
     # 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()

Modified: django/branches/newforms-admin/django/db/models/query.py
===================================================================
--- django/branches/newforms-admin/django/db/models/query.py    2007-01-23 
02:30:55 UTC (rev 4399)
+++ django/branches/newforms-admin/django/db/models/query.py    2007-01-23 
04:31:02 UTC (rev 4400)
@@ -25,6 +25,9 @@
 # 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 @@
         extra_select = self._select.items()
 
         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)
         fill_cache = self._select_related
         index_end = len(self.model._meta.fields)
@@ -192,7 +200,12 @@
         counter._offset = None
         counter._limit = None
         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()
         if self._distinct:
             id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
@@ -523,7 +536,12 @@
             field_names = [f.attname for f in self.model._meta.fields]
 
         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]
         cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + 
",".join(select) + sql, params)
         while 1:
@@ -545,7 +563,12 @@
         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)))
-        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' % \
             (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)
@@ -562,7 +585,26 @@
         c._kind = self._kind
         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 @@
     def get_sql(self, opts):
         joins, where, params = SortedDict(), [], []
         for val in self.args:
-            joins2, where2, params2 = val.get_sql(opts)
-            joins.update(joins2)
-            where.extend(where2)
-            params.extend(params2)
+            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 @@
         self.q = q
 
     def get_sql(self, opts):
-        joins, where, params = self.q.get_sql(opts)
-        where2 = ['(NOT (%s))' % " AND ".join(where)]
+        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 @@
         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'):

Modified: django/branches/newforms-admin/django/oldforms/__init__.py
===================================================================
--- django/branches/newforms-admin/django/oldforms/__init__.py  2007-01-23 
02:30:55 UTC (rev 4399)
+++ django/branches/newforms-admin/django/oldforms/__init__.py  2007-01-23 
04:31:02 UTC (rev 4400)
@@ -569,7 +569,7 @@
     "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):

Modified: django/branches/newforms-admin/docs/db-api.txt
===================================================================
--- django/branches/newforms-admin/docs/db-api.txt      2007-01-23 02:30:55 UTC 
(rev 4399)
+++ django/branches/newforms-admin/docs/db-api.txt      2007-01-23 04:31:02 UTC 
(rev 4400)
@@ -525,7 +525,22 @@
     [datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
     >>> 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()``
 ~~~~~~~~~~~~~~~~~~~~
 

Modified: django/branches/newforms-admin/docs/generic_views.txt
===================================================================
--- django/branches/newforms-admin/docs/generic_views.txt       2007-01-23 
02:30:55 UTC (rev 4399)
+++ django/branches/newforms-admin/docs/generic_views.txt       2007-01-23 
04:31:02 UTC (rev 4400)
@@ -99,7 +99,7 @@
       dictionary is callable, the generic view will call it
       just before rendering the template. (**This is new in the
       Django development version.**)
-      
+
 **Example:**
 
 Given the following URL patterns::
@@ -205,11 +205,11 @@
 ``<app_label>/<model_name>_archive.html`` by default, where:
 
     * ``<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
-        your model's app. For example, if your model lives in
-        ``apps/blog/models.py``, that'd be ``blog``.
+      your model's app. For example, if your model lives in
+      ``apps/blog/models.py``, that'd be ``blog``.
 
 **Template context:**
 
@@ -266,9 +266,9 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``template_object_name``:  Designates the name of the template variable
-       to use in the template context. By default, this is ``'object'``. The
-       view will append ``'_list'`` to the value of this parameter in
-       determining the variable's name.
+      to use in the template context. By default, this is ``'object'``. The
+      view will append ``'_list'`` to the value of this parameter in
+      determining the variable's name.
 
     * ``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``,
@@ -360,9 +360,9 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``template_object_name``:  Designates the name of the template variable
-       to use in the template context. By default, this is ``'object'``. The
-       view will append ``'_list'`` to the value of this parameter in
-       determining the variable's name.
+      to use in the template context. By default, this is ``'object'``. The
+      view will append ``'_list'`` to the value of this parameter in
+      determining the variable's name.
 
     * ``mimetype``: The MIME type to use for the resulting document. Defaults
       to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@@ -441,9 +441,9 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``template_object_name``:  Designates the name of the template variable
-       to use in the template context. By default, this is ``'object'``. The
-       view will append ``'_list'`` to the value of this parameter in
-       determining the variable's name.
+      to use in the template context. By default, this is ``'object'``. The
+      view will append ``'_list'`` to the value of this parameter in
+      determining the variable's name.
 
     * ``mimetype``: The MIME type to use for the resulting document. Defaults
       to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@@ -526,9 +526,9 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``template_object_name``:  Designates the name of the template variable
-       to use in the template context. By default, this is ``'object'``. The
-       view will append ``'_list'`` to the value of this parameter in
-       determining the variable's name.
+      to use in the template context. By default, this is ``'object'``. The
+      view will append ``'_list'`` to the value of this parameter in
+      determining the variable's name.
 
     * ``mimetype``: The MIME type to use for the resulting document. Defaults
       to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@@ -638,7 +638,7 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``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
       to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@@ -710,9 +710,9 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``template_object_name``:  Designates the name of the template variable
-       to use in the template context. By default, this is ``'object'``. The
-       view will append ``'_list'`` to the value of this parameter in
-       determining the variable's name.
+      to use in the template context. By default, this is ``'object'``. The
+      view will append ``'_list'`` to the value of this parameter in
+      determining the variable's name.
 
     * ``mimetype``: The MIME type to use for the resulting document. Defaults
       to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@@ -824,7 +824,7 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``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
       to the value of the ``DEFAULT_CONTENT_TYPE`` setting.
@@ -973,7 +973,7 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``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:**
 
@@ -1054,7 +1054,7 @@
       the view's template. See the `RequestContext docs`_.
 
     * ``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:**
 

Modified: django/branches/newforms-admin/docs/model-api.txt
===================================================================
--- django/branches/newforms-admin/docs/model-api.txt   2007-01-23 02:30:55 UTC 
(rev 4399)
+++ django/branches/newforms-admin/docs/model-api.txt   2007-01-23 04:31:02 UTC 
(rev 4400)
@@ -1408,8 +1408,11 @@
 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
 insensitive, where each word must be in at least one of ``search_fields``. For

Modified: django/branches/newforms-admin/docs/settings.txt
===================================================================
--- django/branches/newforms-admin/docs/settings.txt    2007-01-23 02:30:55 UTC 
(rev 4399)
+++ django/branches/newforms-admin/docs/settings.txt    2007-01-23 04:31:02 UTC 
(rev 4400)
@@ -557,6 +557,11 @@
 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
 ------------------
 

Modified: django/branches/newforms-admin/docs/tutorial03.txt
===================================================================
--- django/branches/newforms-admin/docs/tutorial03.txt  2007-01-23 02:30:55 UTC 
(rev 4399)
+++ django/branches/newforms-admin/docs/tutorial03.txt  2007-01-23 04:31:02 UTC 
(rev 4400)
@@ -260,8 +260,7 @@
         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

Modified: django/branches/newforms-admin/docs/url_dispatch.txt
===================================================================
--- django/branches/newforms-admin/docs/url_dispatch.txt        2007-01-23 
02:30:55 UTC (rev 4399)
+++ django/branches/newforms-admin/docs/url_dispatch.txt        2007-01-23 
04:31:02 UTC (rev 4400)
@@ -393,7 +393,7 @@
 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 @@
 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

Modified: django/branches/newforms-admin/tests/modeltests/lookup/models.py
===================================================================
--- django/branches/newforms-admin/tests/modeltests/lookup/models.py    
2007-01-23 02:30:55 UTC (rev 4399)
+++ django/branches/newforms-admin/tests/modeltests/lookup/models.py    
2007-01-23 04:31:02 UTC (rev 4400)
@@ -191,4 +191,19 @@
 >>> 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>]
+
 """}


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to