Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

newforms-admin: Merged from trunk up to [7808]. Fixed #7519, #7573

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 829fd5a9670a581309797f56bfc7e5140550e873 1 parent c349ba4
Brian Rosner authored June 30, 2008

Showing 60 changed files with 4,333 additions and 1,979 deletions. Show diff stats Hide diff stats

  1. 2  AUTHORS
  2. BIN  django/conf/locale/mk/LC_MESSAGES/django.mo
  3. 5,074  django/conf/locale/mk/LC_MESSAGES/django.po
  4. 2  django/contrib/auth/admin.py
  5. 56  django/contrib/auth/fixtures/authtestdata.json
  6. 6  django/contrib/auth/models.py
  7. 6  django/contrib/auth/tests/__init__.py
  8. 23  django/contrib/auth/tests/basic.py
  9. 29  django/contrib/auth/tests/forms.py
  10. 13  django/contrib/auth/urls.py
  11. 2  django/contrib/flatpages/models.py
  12. 6  django/contrib/formtools/tests.py
  13. 4  django/core/management/commands/createcachetable.py
  14. 6  django/core/management/commands/loaddata.py
  15. 13  django/core/management/sql.py
  16. 3  django/core/servers/basehttp.py
  17. 4  django/core/servers/fastcgi.py
  18. 5  django/core/urlresolvers.py
  19. 2  django/db/backends/__init__.py
  20. 3  django/db/backends/mysql/base.py
  21. 3  django/db/backends/mysql_old/base.py
  22. 1  django/db/backends/oracle/base.py
  23. 2  django/db/backends/oracle/creation.py
  24. 2  django/db/backends/postgresql/operations.py
  25. 32  django/db/models/base.py
  26. 20  django/db/models/fields/__init__.py
  27. 35  django/db/models/fields/related.py
  28. 37  django/db/models/options.py
  29. 5  django/db/models/query.py
  30. 17  django/db/models/query_utils.py
  31. 178  django/db/models/sql/query.py
  32. 12  django/db/models/sql/subqueries.py
  33. 26  django/db/models/sql/where.py
  34. 5  django/db/transaction.py
  35. 4  django/middleware/http.py
  36. 10  django/newforms/fields.py
  37. 25  django/test/testcases.py
  38. 9  django/utils/daemonize.py
  39. 8  docs/apache_auth.txt
  40. 25  docs/db-api.txt
  41. 7  docs/flatpages.txt
  42. 2  docs/model-api.txt
  43. 31  docs/testing.txt
  44. 0  tests/regressiontests/extra_regress/__init__.py
  45. 55  tests/regressiontests/extra_regress/models.py
  46. 83  tests/regressiontests/fixtures_regress/fixtures/big-fixture.json
  47. 4  tests/regressiontests/fixtures_regress/fixtures/model-inheritance.json
  48. 48  tests/regressiontests/fixtures_regress/models.py
  49. 2  tests/regressiontests/forms/error_messages.py
  50. 14  tests/regressiontests/forms/fields.py
  51. 40  tests/regressiontests/many_to_one_regress/models.py
  52. 17  tests/regressiontests/model_fields/tests.py
  53. 22  tests/regressiontests/model_inheritance_regress/models.py
  54. 0  tests/regressiontests/model_inheritance_select_related/__init__.py
  55. 47  tests/regressiontests/model_inheritance_select_related/models.py
  56. 140  tests/regressiontests/queries/models.py
  57. 0  tests/regressiontests/select_related_regress/__init__.py
  58. 60  tests/regressiontests/select_related_regress/models.py
  59. 6  tests/regressiontests/string_lookup/models.py
  60. 19  tests/regressiontests/test_client_regress/models.py
2  AUTHORS
@@ -95,6 +95,7 @@ answer newbie questions, and generally made Django that much better:
95 95
     Sengtha Chay <sengtha@e-khmer.com>
96 96
     ivan.chelubeev@gmail.com
97 97
     Bryan Chow <bryan at verdjn dot com>
  98
+    Antonis Christofides <anthony@itia.ntua.gr>
98 99
     Michal Chruszcz <troll@pld-linux.org>
99 100
     Can Burak Çilingir <canburak@cs.bilgi.edu.tr>
100 101
     Ian Clelland <clelland@gmail.com>
@@ -195,6 +196,7 @@ answer newbie questions, and generally made Django that much better:
195 196
     jcrasta@gmail.com
196 197
     jdetaeye
197 198
     Zak Johnson <zakj@nox.cx>
  199
+    Nis Jørgensen <nis@superlativ.dk>
198 200
     Michael Josephson <http://www.sdjournal.com/>
199 201
     jpellerin@gmail.com
200 202
     junzhang.jn@gmail.com
BIN  django/conf/locale/mk/LC_MESSAGES/django.mo
Binary file not shown
5,074  django/conf/locale/mk/LC_MESSAGES/django.po
3336 additions, 1738 deletions not shown
2  django/contrib/auth/admin.py
@@ -8,6 +8,7 @@
8 8
 
9 9
 class GroupAdmin(admin.ModelAdmin):
10 10
     search_fields = ('name',)
  11
+    ordering = ('name',)
11 12
     filter_horizontal = ('permissions',)
12 13
 
13 14
 class UserAdmin(admin.ModelAdmin):
@@ -21,6 +22,7 @@ class UserAdmin(admin.ModelAdmin):
21 22
     list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
22 23
     list_filter = ('is_staff', 'is_superuser')
23 24
     search_fields = ('username', 'first_name', 'last_name', 'email')
  25
+    ordering = ('username',)
24 26
     filter_horizontal = ('user_permissions',)
25 27
 
26 28
     def add_view(self, request):
56  django/contrib/auth/fixtures/authtestdata.json
... ...
@@ -0,0 +1,56 @@
  1
+[
  2
+    {
  3
+        "pk": "1", 
  4
+        "model": "auth.user", 
  5
+        "fields": {
  6
+            "username": "testclient", 
  7
+            "first_name": "Test", 
  8
+            "last_name": "Client", 
  9
+            "is_active": true, 
  10
+            "is_superuser": false, 
  11
+            "is_staff": false, 
  12
+            "last_login": "2006-12-17 07:03:31", 
  13
+            "groups": [], 
  14
+            "user_permissions": [], 
  15
+            "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161", 
  16
+            "email": "testclient@example.com", 
  17
+            "date_joined": "2006-12-17 07:03:31"
  18
+        }
  19
+    },
  20
+    {
  21
+        "pk": "2", 
  22
+        "model": "auth.user", 
  23
+        "fields": {
  24
+            "username": "inactive", 
  25
+            "first_name": "Inactive", 
  26
+            "last_name": "User", 
  27
+            "is_active": false, 
  28
+            "is_superuser": false, 
  29
+            "is_staff": false, 
  30
+            "last_login": "2006-12-17 07:03:31", 
  31
+            "groups": [], 
  32
+            "user_permissions": [], 
  33
+            "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161", 
  34
+            "email": "testclient@example.com", 
  35
+            "date_joined": "2006-12-17 07:03:31"
  36
+        }
  37
+    },
  38
+    {
  39
+        "pk": "3", 
  40
+        "model": "auth.user", 
  41
+        "fields": {
  42
+            "username": "staff", 
  43
+            "first_name": "Staff", 
  44
+            "last_name": "Member", 
  45
+            "is_active": true, 
  46
+            "is_superuser": false, 
  47
+            "is_staff": true, 
  48
+            "last_login": "2006-12-17 07:03:31", 
  49
+            "groups": [], 
  50
+            "user_permissions": [], 
  51
+            "password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161", 
  52
+            "email": "staffmember@example.com", 
  53
+            "date_joined": "2006-12-17 07:03:31"
  54
+        }
  55
+    }
  56
+]
6  django/contrib/auth/models.py
@@ -96,8 +96,7 @@ class Group(models.Model):
96 96
     class Meta:
97 97
         verbose_name = _('group')
98 98
         verbose_name_plural = _('groups')
99  
-        ordering = ('name',)
100  
-
  99
+        
101 100
     def __unicode__(self):
102 101
         return self.name
103 102
 
@@ -150,8 +149,7 @@ class User(models.Model):
150 149
     class Meta:
151 150
         verbose_name = _('user')
152 151
         verbose_name_plural = _('users')
153  
-        ordering = ('username',)
154  
-
  152
+        
155 153
     def __unicode__(self):
156 154
         return self.username
157 155
 
6  django/contrib/auth/tests/__init__.py
... ...
@@ -1,8 +1,8 @@
1  
-from django.contrib.auth.tests.basic import BASIC_TESTS
2  
-from django.contrib.auth.tests.forms import FORM_TESTS, PasswordResetFormTestCase
  1
+from django.contrib.auth.tests.basic import BASIC_TESTS, PasswordResetTest
  2
+from django.contrib.auth.tests.forms import FORM_TESTS
3 3
 
4 4
 __test__ = {
5 5
     'BASIC_TESTS': BASIC_TESTS,
6  
-    'PASSWORDRESET_TESTS': PasswordResetFormTestCase,
  6
+    'PASSWORDRESET_TESTS': PasswordResetTest,
7 7
     'FORM_TESTS': FORM_TESTS,
8 8
 }
23  django/contrib/auth/tests/basic.py
@@ -53,4 +53,25 @@
53 53
 u'joe@somewhere.org'
54 54
 >>> u.password
55 55
 u'!'
56  
-"""
  56
+"""
  57
+
  58
+from django.test import TestCase
  59
+from django.core import mail
  60
+
  61
+class PasswordResetTest(TestCase):
  62
+    fixtures = ['authtestdata.json']
  63
+    urls = 'django.contrib.auth.urls'
  64
+    
  65
+    def test_email_not_found(self):
  66
+        "Error is raised if the provided email address isn't currently registered"
  67
+        response = self.client.get('/password_reset/')
  68
+        self.assertEquals(response.status_code, 200)
  69
+        response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
  70
+        self.assertContains(response, "That e-mail address doesn't have an associated user account")
  71
+        self.assertEquals(len(mail.outbox), 0)
  72
+    
  73
+    def test_email_found(self):
  74
+        "Email is sent if a valid email address is provided for password reset"
  75
+        response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
  76
+        self.assertEquals(response.status_code, 302)
  77
+        self.assertEquals(len(mail.outbox), 1)
29  django/contrib/auth/tests/forms.py
... ...
@@ -1,33 +1,4 @@
1 1
 
2  
-from django.core import mail
3  
-from django.test import TestCase
4  
-from django.contrib.auth.models import User
5  
-from django.contrib.auth.forms import PasswordResetForm
6  
-
7  
-class PasswordResetFormTestCase(TestCase):
8  
-    def testValidUser(self):
9  
-        data = {
10  
-            'email': 'nonexistent@example.com',
11  
-        }
12  
-        form = PasswordResetForm(data)
13  
-        self.assertEqual(form.is_valid(), False)
14  
-        self.assertEqual(form["email"].errors, [u"That e-mail address doesn't have an associated user account. Are you sure you've registered?"])
15  
-    
16  
-    def testEmail(self):
17  
-        # TODO: remove my email address from the test ;)
18  
-        User.objects.create_user('atestuser', 'atestuser@example.com', 'test789')
19  
-        data = {
20  
-            'email': 'atestuser@example.com',
21  
-        }
22  
-        form = PasswordResetForm(data)
23  
-        self.assertEqual(form.is_valid(), True)
24  
-        # TODO: look at why using contrib.sites breaks other tests
25  
-        form.save(domain_override="example.com")
26  
-        self.assertEqual(len(mail.outbox), 1)
27  
-        self.assertEqual(mail.outbox[0].subject, u'Password reset on example.com')
28  
-        # TODO: test mail body. need to figure out a way to get the password in plain text
29  
-        # self.assertEqual(mail.outbox[0].body, '')
30  
-
31 2
 FORM_TESTS = """
32 3
 >>> from django.contrib.auth.models import User
33 4
 >>> from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
13  django/contrib/auth/urls.py
... ...
@@ -0,0 +1,13 @@
  1
+# These URLs are normally mapped to /admin/urls.py. This URLs file is 
  2
+# provided as a convenience to those who want to deploy these URLs elsewhere.
  3
+# This file is also used to provide a reliable view deployment for test purposes.
  4
+
  5
+from django.conf.urls.defaults import *
  6
+
  7
+urlpatterns = patterns('',
  8
+    ('^logout/$', 'django.contrib.auth.views.logout'),
  9
+    ('^password_change/$', 'django.contrib.auth.views.password_change'),
  10
+    ('^password_change/done/$', 'django.contrib.auth.views.password_change_done'),
  11
+    ('^password_reset/$', 'django.contrib.auth.views.password_reset')
  12
+)
  13
+
2  django/contrib/flatpages/models.py
@@ -8,7 +8,7 @@ class FlatPage(models.Model):
8 8
     url = models.CharField(_('URL'), max_length=100, validator_list=[validators.isAlphaNumericURL], db_index=True,
9 9
         help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes."))
10 10
     title = models.CharField(_('title'), max_length=200)
11  
-    content = models.TextField(_('content'))
  11
+    content = models.TextField(_('content'), blank=True)
12 12
     enable_comments = models.BooleanField(_('enable comments'))
13 13
     template_name = models.CharField(_('template name'), max_length=70, blank=True,
14 14
         help_text=_("Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."))
6  django/contrib/formtools/tests.py
@@ -21,18 +21,14 @@ class TestForm(forms.Form):
21 21
 
22 22
 
23 23
 class PreviewTests(TestCase):
  24
+    urls = 'django.contrib.formtools.test_urls'
24 25
 
25 26
     def setUp(self):
26  
-        self._old_root_urlconf = settings.ROOT_URLCONF
27  
-        settings.ROOT_URLCONF = 'django.contrib.formtools.test_urls'
28 27
         # Create a FormPreview instance to share between tests
29 28
         self.preview = preview.FormPreview(TestForm)
30 29
         input_template = '<input type="hidden" name="%s" value="%s" />'
31 30
         self.input = input_template % (self.preview.unused_name('stage'), "%d")
32 31
 
33  
-    def tearDown(self):
34  
-        settings.ROOT_URLCONF = self._old_root_urlconf
35  
-        
36 32
     def test_unused_name(self):
37 33
         """
38 34
         Verifies name mangling to get uniue field name.
4  django/core/management/commands/createcachetable.py
@@ -21,10 +21,10 @@ def handle_label(self, tablename, **options):
21 21
         for f in fields:
22 22
             field_output = [qn(f.name), f.db_type()]
23 23
             field_output.append("%sNULL" % (not f.null and "NOT " or ""))
24  
-            if f.unique:
25  
-                field_output.append("UNIQUE")
26 24
             if f.primary_key:
27 25
                 field_output.append("PRIMARY KEY")
  26
+            elif f.unique:
  27
+                field_output.append("UNIQUE")
28 28
             if f.db_index:
29 29
                 unique = f.unique and "UNIQUE " or ""
30 30
                 index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
6  django/core/management/commands/loaddata.py
@@ -162,3 +162,9 @@ def handle(self, *fixture_labels, **options):
162 162
         else:
163 163
             if verbosity > 0:
164 164
                 print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)
  165
+                
  166
+        # Close the DB connection. This is required as a workaround for an
  167
+        # edge case in MySQL: if the same connection is used to
  168
+        # create tables, load data, and query, the query can return
  169
+        # incorrect results. See Django #7572, MySQL #37735.
  170
+        connection.close()
13  django/core/management/sql.py
@@ -268,11 +268,11 @@ def sql_model_create(model, style, known_models=set()):
268 268
         field_output = [style.SQL_FIELD(qn(f.column)),
269 269
             style.SQL_COLTYPE(col_type)]
270 270
         field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
271  
-        if f.unique and (not f.primary_key or connection.features.allows_unique_and_pk):
272  
-            field_output.append(style.SQL_KEYWORD('UNIQUE'))
273 271
         if f.primary_key:
274 272
             field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
275  
-        if tablespace and connection.features.supports_tablespaces and (f.unique or f.primary_key) and connection.features.autoindexes_primary_keys:
  273
+        elif f.unique:
  274
+            field_output.append(style.SQL_KEYWORD('UNIQUE'))
  275
+        if tablespace and connection.features.supports_tablespaces and f.unique:
276 276
             # We must specify the index tablespace inline, because we
277 277
             # won't be generating a CREATE INDEX statement for this field.
278 278
             field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
@@ -355,7 +355,7 @@ def many_to_many_sql_for_model(model, style):
355 355
     for f in opts.local_many_to_many:
356 356
         if not isinstance(f.rel, generic.GenericRel):
357 357
             tablespace = f.db_tablespace or opts.db_tablespace
358  
-            if tablespace and connection.features.supports_tablespaces and connection.features.autoindexes_primary_keys:
  358
+            if tablespace and connection.features.supports_tablespaces: 
359 359
                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)
360 360
             else:
361 361
                 tablespace_sql = ''
@@ -460,15 +460,14 @@ def sql_indexes_for_model(model, style):
460 460
 
461 461
     qn = connection.ops.quote_name
462 462
     for f in model._meta.local_fields:
463  
-        if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
464  
-            unique = f.unique and 'UNIQUE ' or ''
  463
+        if f.db_index and not f.unique:
465 464
             tablespace = f.db_tablespace or model._meta.db_tablespace
466 465
             if tablespace and connection.features.supports_tablespaces:
467 466
                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
468 467
             else:
469 468
                 tablespace_sql = ''
470 469
             output.append(
471  
-                style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
  470
+                style.SQL_KEYWORD('CREATE INDEX') + ' ' + \
472 471
                 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
473 472
                 style.SQL_KEYWORD('ON') + ' ' + \
474 473
                 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
3  django/core/servers/basehttp.py
@@ -551,6 +551,9 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
551 551
     def __init__(self, *args, **kwargs):
552 552
         from django.conf import settings
553 553
         self.admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
  554
+        # We set self.path to avoid crashes in log_message() on unsupported
  555
+        # requests (like "OPTIONS").
  556
+        self.path = ''
554 557
         BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
555 558
 
556 559
     def get_environ(self):
4  django/core/servers/fastcgi.py
@@ -40,6 +40,7 @@
40 40
   workdir=DIRECTORY    change to this directory when daemonizing.
41 41
   outlog=FILE          write stdout to this file.
42 42
   errlog=FILE          write stderr to this file.
  43
+  umask=UMASK          umask to use when daemonizing (default 022).
43 44
 
44 45
 Examples:
45 46
   Run a "standard" fastcgi process on a file-descriptor
@@ -73,6 +74,7 @@
73 74
     'maxrequests': 0,
74 75
     'outlog': None,
75 76
     'errlog': None,
  77
+    'umask': None,
76 78
 }
77 79
 
78 80
 def fastcgi_help(message=None):
@@ -159,6 +161,8 @@ def runfastcgi(argset=[], **kwargs):
159 161
         daemon_kwargs['out_log'] = options['outlog']
160 162
     if options['errlog']:
161 163
         daemon_kwargs['err_log'] = options['errlog']
  164
+    if options['umask']:
  165
+        daemon_kwargs['umask'] = int(options['umask'])
162 166
 
163 167
     if daemonize:
164 168
         from django.utils.daemonize import become_daemon
5  django/core/urlresolvers.py
@@ -296,3 +296,8 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None):
296 296
     kwargs = kwargs or {}
297 297
     return iri_to_uri(u'/' + get_resolver(urlconf).reverse(viewname, *args, **kwargs))
298 298
 
  299
+def clear_url_caches():
  300
+    global _resolver_cache
  301
+    global _callable_cache
  302
+    _resolver_cache.clear()
  303
+    _callable_cache.clear()
2  django/db/backends/__init__.py
@@ -41,8 +41,6 @@ def make_debug_cursor(self, cursor):
41 41
 
42 42
 class BaseDatabaseFeatures(object):
43 43
     allows_group_by_ordinal = True
44  
-    allows_unique_and_pk = True
45  
-    autoindexes_primary_keys = True
46 44
     inline_fk_references = True
47 45
     needs_datetime_string_cast = True
48 46
     supports_constraints = True
3  django/db/backends/mysql/base.py
@@ -60,7 +60,6 @@
60 60
 # TRADITIONAL will automatically cause most warnings to be treated as errors.
61 61
 
62 62
 class DatabaseFeatures(BaseDatabaseFeatures):
63  
-    autoindexes_primary_keys = False
64 63
     inline_fk_references = False
65 64
     empty_fetchmany_value = ()
66 65
     update_can_self_select = False
@@ -136,7 +135,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
136 135
     features = DatabaseFeatures()
137 136
     ops = DatabaseOperations()
138 137
     operators = {
139  
-        'exact': '= %s',
  138
+        'exact': '= BINARY %s',
140 139
         'iexact': 'LIKE %s',
141 140
         'contains': 'LIKE BINARY %s',
142 141
         'icontains': 'LIKE %s',
3  django/db/backends/mysql_old/base.py
@@ -64,7 +64,6 @@ def __getattr__(self, attr):
64 64
             return getattr(self.cursor, attr)
65 65
 
66 66
 class DatabaseFeatures(BaseDatabaseFeatures):
67  
-    autoindexes_primary_keys = False
68 67
     inline_fk_references = False
69 68
     empty_fetchmany_value = ()
70 69
     update_can_self_select = False
@@ -140,7 +139,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
140 139
     features = DatabaseFeatures()
141 140
     ops = DatabaseOperations()
142 141
     operators = {
143  
-        'exact': '= %s',
  142
+        'exact': '= BINARY %s',
144 143
         'iexact': 'LIKE %s',
145 144
         'contains': 'LIKE BINARY %s',
146 145
         'icontains': 'LIKE %s',
1  django/db/backends/oracle/base.py
@@ -24,7 +24,6 @@
24 24
 
25 25
 class DatabaseFeatures(BaseDatabaseFeatures):
26 26
     allows_group_by_ordinal = False
27  
-    allows_unique_and_pk = False        # Suppress UNIQUE/PK for Oracle (ORA-02259)
28 27
     empty_fetchmany_value = ()
29 28
     needs_datetime_string_cast = False
30 29
     supports_tablespaces = True
2  django/db/backends/oracle/creation.py
@@ -23,7 +23,7 @@
23 23
     'ImageField':                   'NVARCHAR2(%(max_length)s)',
24 24
     'IntegerField':                 'NUMBER(11)',
25 25
     'IPAddressField':               'VARCHAR2(15)',
26  
-    'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(column)s IS NULL))',
  26
+    'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))',
27 27
     'OneToOneField':                'NUMBER(11)',
28 28
     'PhoneNumberField':             'VARCHAR2(20)',
29 29
     'PositiveIntegerField':         'NUMBER(11) CHECK (%(qn_column)s >= 0)',
2  django/db/backends/postgresql/operations.py
@@ -97,7 +97,7 @@ def sequence_reset_sql(self, style, model_list):
97 97
             # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
98 98
             # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
99 99
             # if there are records (as the max pk value is already in use), otherwise set it to false.
100  
-            for f in model._meta.fields:
  100
+            for f in model._meta.local_fields:
101 101
                 if isinstance(f, models.AutoField):
102 102
                     output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
103 103
                         (style.SQL_KEYWORD('SELECT'),
32  django/db/models/base.py
@@ -50,7 +50,15 @@ def __new__(cls, name, bases, attrs):
50 50
             meta = attr_meta
51 51
         base_meta = getattr(new_class, '_meta', None)
52 52
 
53  
-        new_class.add_to_class('_meta', Options(meta))
  53
+        if getattr(meta, 'app_label', None) is None:
  54
+            # Figure out the app_label by looking one level up.
  55
+            # For 'django.contrib.sites.models', this would be 'sites'.
  56
+            model_module = sys.modules[new_class.__module__]
  57
+            kwargs = {"app_label": model_module.__name__.split('.')[-2]}
  58
+        else:
  59
+            kwargs = {}
  60
+
  61
+        new_class.add_to_class('_meta', Options(meta, **kwargs))
54 62
         if not abstract:
55 63
             new_class.add_to_class('DoesNotExist',
56 64
                     subclass_exception('DoesNotExist', ObjectDoesNotExist, module))
@@ -71,11 +79,6 @@ def __new__(cls, name, bases, attrs):
71 79
             if new_class._default_manager.model._meta.abstract:
72 80
                 old_default_mgr = new_class._default_manager
73 81
             new_class._default_manager = None
74  
-        if getattr(new_class._meta, 'app_label', None) is None:
75  
-            # Figure out the app_label by looking one level up.
76  
-            # For 'django.contrib.sites.models', this would be 'sites'.
77  
-            model_module = sys.modules[new_class.__module__]
78  
-            new_class._meta.app_label = model_module.__name__.split('.')[-2]
79 82
 
80 83
         # Bail out early if we have already created this class.
81 84
         m = get_model(new_class._meta.app_label, name, False)
@@ -389,6 +392,21 @@ def _collect_sub_objects(self, seen_objs, parent=None, nullable=False):
389 392
                 for sub_obj in getattr(self, rel_opts_name).all():
390 393
                     sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null)
391 394
 
  395
+        # Handle any ancestors (for the model-inheritance case). We do this by
  396
+        # traversing to the most remote parent classes -- those with no parents
  397
+        # themselves -- and then adding those instances to the collection. That
  398
+        # will include all the child instances down to "self".
  399
+        parent_stack = self._meta.parents.values()
  400
+        while parent_stack:
  401
+            link = parent_stack.pop()
  402
+            parent_obj = getattr(self, link.name)
  403
+            if parent_obj._meta.parents:
  404
+                parent_stack.extend(parent_obj._meta.parents.values())
  405
+                continue
  406
+            # At this point, parent_obj is base class (no ancestor models). So
  407
+            # delete it and all its descendents.
  408
+            parent_obj._collect_sub_objects(seen_objs)
  409
+
392 410
     def delete(self):
393 411
         assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
394 412
 
@@ -436,7 +454,7 @@ def _get_next_or_previous_in_order(self, is_next):
436 454
 
437 455
     def _get_FIELD_filename(self, field):
438 456
         if getattr(self, field.attname): # value is not blank
439  
-            return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
  457
+            return os.path.normpath(os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname)))
440 458
         return ''
441 459
 
442 460
     def _get_FIELD_url(self, field):
20  django/db/models/fields/__init__.py
@@ -85,7 +85,7 @@ def __init__(self, verbose_name=None, name=None, primary_key=False,
85 85
         self.name = name
86 86
         self.verbose_name = verbose_name
87 87
         self.primary_key = primary_key
88  
-        self.max_length, self.unique = max_length, unique
  88
+        self.max_length, self._unique = max_length, unique
89 89
         self.blank, self.null = blank, null
90 90
         # Oracle treats the empty string ('') as null, so coerce the null
91 91
         # option whenever '' is a possible value.
@@ -160,6 +160,10 @@ def db_type(self):
160 160
         except KeyError:
161 161
             return None
162 162
 
  163
+    def unique(self):
  164
+        return self._unique or self.primary_key
  165
+    unique = property(unique)
  166
+
163 167
     def validate_full(self, field_data, all_data):
164 168
         """
165 169
         Returns a list of errors for this field. This is the main interface,
@@ -676,7 +680,7 @@ def to_python(self, value):
676 680
                 _("This value must be a decimal number."))
677 681
 
678 682
     def _format(self, value):
679  
-        if isinstance(value, basestring):
  683
+        if isinstance(value, basestring) or value is None:
680 684
             return value
681 685
         else:
682 686
             return self.format_number(value)
@@ -697,8 +701,7 @@ def format_number(self, value):
697 701
         return u"%.*f" % (self.decimal_places, value)
698 702
 
699 703
     def get_db_prep_save(self, value):
700  
-        if value is not None:
701  
-            value = self._format(value)
  704
+        value = self._format(value)
702 705
         return super(DecimalField, self).get_db_prep_save(value)
703 706
 
704 707
     def get_db_prep_lookup(self, lookup_type, value):
@@ -1151,12 +1154,3 @@ def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
1151 1154
     def get_manipulator_field_objs(self):
1152 1155
         return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]
1153 1156
 
1154  
-class OrderingField(IntegerField):
1155  
-    empty_strings_allowed=False
1156  
-    def __init__(self, with_respect_to, **kwargs):
1157  
-        self.wrt = with_respect_to
1158  
-        kwargs['null'] = True
1159  
-        IntegerField.__init__(self, **kwargs )
1160  
-
1161  
-    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
1162  
-        return [oldforms.HiddenField(name_prefix + self.name)]
35  django/db/models/fields/related.py
@@ -185,11 +185,11 @@ def __get__(self, instance, instance_type=None):
@@ -197,14 +197,14 @@ def __set__(self, instance, value):
@@ -243,7 +243,7 @@ def __get__(self, instance, instance_type=None):
@@ -251,9 +251,9 @@ def __set__(self, instance, value):
@@ -262,7 +262,7 @@ def __set__(self, instance, value):
@@ -322,7 +322,9 @@ def clear(self):
@@ -670,6 +672,11 @@ def flatten_data(self, follow, obj=None):
@@ -791,6 +798,12 @@ def contribute_to_class(self, cls, name):
37  django/db/models/options.py
@@ -24,7 +24,7 @@
24 24
                  'abstract')
25 25
 
26 26
 class Options(object):
27  
-    def __init__(self, meta):
  27
+    def __init__(self, meta, app_label=None):
28 28
         self.local_fields, self.local_many_to_many = [], []
29 29
         self.module_name, self.verbose_name = None, None
30 30
         self.verbose_name_plural = None
@@ -32,7 +32,7 @@ def __init__(self, meta):
32 32
         self.ordering = []
33 33
         self.unique_together =  []
34 34
         self.permissions =  []
35  
-        self.object_name, self.app_label = None, None
  35
+        self.object_name, self.app_label = None, app_label
36 36
         self.get_latest_by = None
37 37
         self.order_with_respect_to = None
38 38
         self.db_tablespace = settings.DEFAULT_TABLESPACE
@@ -43,8 +43,12 @@ def __init__(self, meta):
43 43
         self.one_to_one_field = None
44 44
         self.abstract = False
45 45
         self.parents = SortedDict()
  46
+        self.duplicate_targets = {}
46 47
 
47 48
     def contribute_to_class(self, cls, name):
  49
+        from django.db import connection
  50
+        from django.db.backends.util import truncate_name
  51
+
48 52
         cls._meta = self
49 53
         self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
50 54
         # First, construct the default values for these options.
@@ -86,9 +90,13 @@ def contribute_to_class(self, cls, name):
86 90
             self.verbose_name_plural = string_concat(self.verbose_name, 's')
87 91
         del self.meta
88 92
 
  93
+        # If the db_table wasn't provided, use the app_label + module_name.
  94
+        if not self.db_table:
  95
+            self.db_table = "%s_%s" % (self.app_label, self.module_name)
  96
+            self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
  97
+
  98
+
89 99
     def _prepare(self, model):
90  
-        from django.db import connection
91  
-        from django.db.backends.util import truncate_name
92 100
         if self.order_with_respect_to:
93 101
             self.order_with_respect_to = self.get_field(self.order_with_respect_to)
94 102
             self.ordering = ('_order',)
@@ -107,10 +115,23 @@ def _prepare(self, model):
107 115
                         auto_created=True)
108 116
                 model.add_to_class('id', auto)
109 117
 
110  
-        # If the db_table wasn't provided, use the app_label + module_name.
111  
-        if not self.db_table:
112  
-            self.db_table = "%s_%s" % (self.app_label, self.module_name)
113  
-            self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
  118
+        # Determine any sets of fields that are pointing to the same targets
  119
+        # (e.g. two ForeignKeys to the same remote model). The query
  120
+        # construction code needs to know this. At the end of this,
  121
+        # self.duplicate_targets will map each duplicate field column to the
  122
+        # columns it duplicates.
  123
+        collections = {}
  124
+        for column, target in self.duplicate_targets.iteritems():
  125
+            try:
  126
+                collections[target].add(column)
  127
+            except KeyError:
  128
+                collections[target] = set([column])
  129
+        self.duplicate_targets = {}
  130
+        for elt in collections.itervalues():
  131
+            if len(elt) == 1:
  132
+                continue
  133
+            for column in elt:
  134
+                self.duplicate_targets[column] = elt.difference(set([column]))
114 135
 
115 136
     def add_field(self, field):
116 137
         # Insert the given field in the order in which it was created, using
5  django/db/models/query.py
@@ -3,7 +3,7 @@
3 3
 from django.conf import settings
4 4
 from django.db import connection, transaction, IntegrityError
5 5
 from django.db.models.fields import DateField, FieldDoesNotExist
6  
-from django.db.models.query_utils import Q
  6
+from django.db.models.query_utils import Q, select_related_descend
7 7
 from django.db.models import signals, sql
8 8
 from django.dispatch import dispatcher
9 9
 from django.utils.datastructures import SortedDict
@@ -761,8 +761,7 @@ def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0,
761 761
     index_end = index_start + len(klass._meta.fields)
762 762
     obj = klass(*row[index_start:index_end])
763 763
     for f in klass._meta.fields:
764  
-        if (not f.rel or (not restricted and f.null) or
765  
-                (restricted and f.name not in requested) or f.rel.parent_link):
  764
+        if not select_related_descend(f, restricted, requested):
766 765
             continue
767 766
         if restricted:
768 767
             next = requested[f.name]
17  django/db/models/query_utils.py
@@ -48,3 +48,20 @@ def __invert__(self):
48 48
         obj.negate()
49 49
         return obj
50 50
 
  51
+def select_related_descend(field, restricted, requested):
  52
+    """
  53
+    Returns True if this field should be used to descend deeper for
  54
+    select_related() purposes. Used by both the query construction code
  55
+    (sql.query.fill_related_selections()) and the model instance creation code
  56
+    (query.get_cached_row()).
  57
+    """
  58
+    if not field.rel:
  59
+        return False
  60
+    if field.rel.parent_link:
  61
+        return False
  62
+    if restricted and field.name not in requested:
  63
+        return False
  64
+    if not restricted and field.null:
  65
+        return False
  66
+    return True
  67
+
178  django/db/models/sql/query.py
@@ -7,6 +7,7 @@
7 7
 all about the internals of models in order to get the information it needs.
8 8
 """
9 9
 
  10
+import datetime
10 11
 from copy import deepcopy
11 12
 
12 13
 from django.utils.tree import Node
@@ -14,9 +15,10 @@
14 15
 from django.dispatch import dispatcher
15 16
 from django.db import connection
16 17
 from django.db.models import signals
  18
+from django.db.models.fields import FieldDoesNotExist
  19
+from django.db.models.query_utils import select_related_descend
17 20
 from django.db.models.sql.where import WhereNode, EverythingNode, AND, OR
18 21
 from django.db.models.sql.datastructures import Count
19  
-from django.db.models.fields import FieldDoesNotExist
20 22
 from django.core.exceptions import FieldError
21 23
 from datastructures import EmptyResultSet, Empty, MultiJoin
22 24
 from constants import *
@@ -56,6 +58,7 @@ def __init__(self, model, connection, where=WhereNode):
56 58
         self.start_meta = None
57 59
         self.select_fields = []
58 60
         self.related_select_fields = []
  61
+        self.dupe_avoidance = {}
59 62
 
60 63
         # SQL-related attributes
61 64
         self.select = []
@@ -164,6 +167,7 @@ def clone(self, klass=None, **kwargs):
164 167
         obj.start_meta = self.start_meta
165 168
         obj.select_fields = self.select_fields[:]
166 169
         obj.related_select_fields = self.related_select_fields[:]
  170
+        obj.dupe_avoidance = self.dupe_avoidance.copy()
167 171
         obj.select = self.select[:]
168 172
         obj.tables = self.tables[:]
169 173
         obj.where = deepcopy(self.where)
@@ -214,7 +218,7 @@ def get_count(self):
214 218
         obj.select_related = False
215 219
         obj.related_select_cols = []
216 220
         obj.related_select_fields = []
217  
-        if obj.distinct and len(obj.select) > 1:
  221
+        if len(obj.select) > 1:
218 222
             obj = self.clone(CountQuery, _query=obj, where=self.where_class(),
219 223
                     distinct=False)
220 224
             obj.select = []
@@ -362,10 +366,21 @@ def combine(self, rhs, connector):
362 366
                 item.relabel_aliases(change_map)
363 367
                 self.select.append(item)
364 368
         self.select_fields = rhs.select_fields[:]
365  
-        self.extra_select = rhs.extra_select.copy()
366  
-        self.extra_tables = rhs.extra_tables
367  
-        self.extra_where = rhs.extra_where
368  
-        self.extra_params = rhs.extra_params
  369
+
  370
+        if connector == OR:
  371
+            # It would be nice to be able to handle this, but the queries don't
  372
+            # really make sense (or return consistent value sets). Not worth
  373
+            # the extra complexity when you can write a real query instead.
  374
+            if self.extra_select and rhs.extra_select:
  375
+                raise ValueError("When merging querysets using 'or', you "
  376
+                        "cannot have extra(select=...) on both sides.")
  377
+            if self.extra_where and rhs.extra_where:
  378
+                raise ValueError("When merging querysets using 'or', you "
  379
+                        "cannot have extra(where=...) on both sides.")
  380
+        self.extra_select.update(rhs.extra_select)
  381
+        self.extra_tables += rhs.extra_tables
  382
+        self.extra_where += rhs.extra_where
  383
+        self.extra_params += rhs.extra_params
369 384
 
370 385
         # Ordering uses the 'rhs' ordering, unless it has none, in which case
371 386
         # the current ordering is used.
@@ -439,28 +454,39 @@ def get_columns(self, with_aliases=False):
439 454
         self._select_aliases = aliases
440 455
         return result
441 456
 
442  
-    def get_default_columns(self, with_aliases=False, col_aliases=None):
  457
+    def get_default_columns(self, with_aliases=False, col_aliases=None,
  458
+            start_alias=None, opts=None, as_pairs=False):
443 459
         """
444 460
         Computes the default columns for selecting every field in the base
445 461
         model.
446 462
 
447 463
         Returns a list of strings, quoted appropriately for use in SQL
448  
-        directly, as well as a set of aliases used in the select statement.
  464
+        directly, as well as a set of aliases used in the select statement (if
  465
+        'as_pairs' is True, returns a list of (alias, col_name) pairs instead
  466
+        of strings as the first component and None as the second component).
449 467
         """
450 468
         result = []
451  
-        table_alias = self.tables[0]
452  
-        root_pk = self.model._meta.pk.column
  469
+        if opts is None:
  470
+            opts = self.model._meta
  471
+        if start_alias:
  472
+            table_alias = start_alias
  473
+        else:
  474
+            table_alias = self.tables[0]
  475
+        root_pk = opts.pk.column
453 476
         seen = {None: table_alias}
454 477
         qn = self.quote_name_unless_alias
455 478
         qn2 = self.connection.ops.quote_name
456 479
         aliases = set()
457  
-        for field, model in self.model._meta.get_fields_with_model():
  480
+        for field, model in opts.get_fields_with_model():
458 481
             try:
459 482
                 alias = seen[model]
460 483
             except KeyError:
461 484
                 alias = self.join((table_alias, model._meta.db_table,
462 485
                         root_pk, model._meta.pk.column))
463 486
                 seen[model] = alias
  487
+            if as_pairs:
  488
+                result.append((alias, field.column))
  489
+                continue
464 490
             if with_aliases and field.column in col_aliases:
465 491
                 c_alias = 'Col%d' % len(col_aliases)
466 492
                 result.append('%s.%s AS %s' % (qn(alias),
@@ -473,6 +499,8 @@ def get_default_columns(self, with_aliases=False, col_aliases=None):
473 499
                 aliases.add(r)
474 500
                 if with_aliases:
475 501
                     col_aliases.add(field.column)
  502
+        if as_pairs:
  503
+            return result, None
476 504
         return result, aliases
477 505
 
478 506
     def get_from_clause(self):
@@ -609,6 +637,11 @@ def find_ordering_name(self, name, opts, alias=None, default_order='ASC',
609 637
                 alias, False)
610 638
         alias = joins[-1]
611 639
         col = target.column
  640
+        if not field.rel:
  641
+            # To avoid inadvertent trimming of a necessary alias, use the
  642
+            # refcount to show that we are referencing a non-relation field on
  643
+            # the model.
  644
+            self.ref_alias(alias)
612 645
 
613 646
         # Must use left outer joins for nullable fields.
614 647
         for join in joins:
@@ -829,8 +862,8 @@ def join(self, connection, always_create=False, exclusions=(),
829 862
 
830 863
         if reuse and always_create and table in self.table_map:
831 864
             # Convert the 'reuse' to case to be "exclude everything but the
832  
-            # reusable set for this table".
833  
-            exclusions = set(self.table_map[table]).difference(reuse)
  865
+            # reusable set, minus exclusions, for this table".
  866
+            exclusions = set(self.table_map[table]).difference(reuse).union(set(exclusions))
834 867
             always_create = False
835 868
         t_ident = (lhs_table, table, lhs_col, col)
836 869
         if not always_create:
@@ -865,7 +898,8 @@ def join(self, connection, always_create=False, exclusions=(),
865 898
         return alias
866 899
 
867 900
     def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
868  
-            used=None, requested=None, restricted=None, nullable=None):
  901
+            used=None, requested=None, restricted=None, nullable=None,
  902
+            dupe_set=None):
869 903
         """
870 904
         Fill in the information needed for a select_related query. The current
871 905
         depth is measured as the number of connections away from the root model
@@ -875,6 +909,7 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
875 909
         if not restricted and self.max_depth and cur_depth > self.max_depth:
876 910
             # We've recursed far enough; bail out.
877 911
             return
  912
+
878 913
         if not opts:
879 914
             opts = self.get_meta()
880 915
             root_alias = self.get_initial_alias()
@@ -882,6 +917,10 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
882 917
             self.related_select_fields = []
883 918
         if not used:
884 919
             used = set()
  920
+        if dupe_set is None:
  921
+            dupe_set = set()
  922
+        orig_dupe_set = dupe_set
  923
+        orig_used = used
885 924
 
886 925
         # Setup for the case when only particular related fields should be
887 926
         # included in the related selection.
@@ -893,9 +932,10 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
893 932
                 restricted = False
894 933
 
895 934
         for f, model in opts.get_fields_with_model():
896  
-            if (not f.rel or (restricted and f.name not in requested) or
897  
-                    (not restricted and f.null) or f.rel.parent_link):
  935
+            if not select_related_descend(f, restricted, requested):
898 936
                 continue
  937
+            dupe_set = orig_dupe_set.copy()
  938
+            used = orig_used.copy()
899 939
             table = f.rel.to._meta.db_table
900 940
             if nullable or f.null:
901 941
                 promote = True
@@ -906,18 +946,32 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
906 946
                 alias = root_alias
907 947
                 for int_model in opts.get_base_chain(model):
908 948
                     lhs_col = int_opts.parents[int_model].column
  949
+                    dedupe = lhs_col in opts.duplicate_targets
  950
+                    if dedupe:
  951
+                        used.update(self.dupe_avoidance.get(id(opts), lhs_col),
  952
+                                ())
  953
+                        dupe_set.add((opts, lhs_col))
909 954
                     int_opts = int_model._meta
910 955
                     alias = self.join((alias, int_opts.db_table, lhs_col,
911 956
                             int_opts.pk.column), exclusions=used,
912 957
                             promote=promote)
  958
+                    for (dupe_opts, dupe_col) in dupe_set:
  959
+                        self.update_dupe_avoidance(dupe_opts, dupe_col, alias)
913 960
             else:
914 961
                 alias = root_alias
  962
+
  963
+            dedupe = f.column in opts.duplicate_targets
  964
+            if dupe_set or dedupe:
  965
+                used.update(self.dupe_avoidance.get((id(opts), f.column), ()))
  966
+                if dedupe:
  967
+                    dupe_set.add((opts, f.column))
  968
+
915 969
             alias = self.join((alias, table, f.column,
916 970
                     f.rel.get_related_field().column), exclusions=used,
917 971
                     promote=promote)
918 972
             used.add(alias)
919  
-            self.related_select_cols.extend([(alias, f2.column)
920  
-                    for f2 in f.rel.to._meta.fields])
  973
+            self.related_select_cols.extend(self.get_default_columns(
  974
+                start_alias=alias, opts=f.rel.to._meta, as_pairs=True)[0])
921 975
             self.related_select_fields.extend(f.rel.to._meta.fields)
922 976
             if restricted:
923 977
                 next = requested.get(f.name, {})
@@ -927,8 +981,10 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
927 981
                 new_nullable = f.null
928 982
             else:
929 983
                 new_nullable = None
  984
+            for dupe_opts, dupe_col in dupe_set:
  985
+                self.update_dupe_avoidance(dupe_opts, dupe_col, alias)
930 986
             self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
931  
-                    used, next, restricted, new_nullable)
  987
+                    used, next, restricted, new_nullable, dupe_set)
932 988
 
933 989
     def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
934 990
             can_reuse=None):
@@ -1048,7 +1104,19 @@ def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
1048 1104
                 # that's harmless.
1049 1105
                 self.promote_alias(table)
1050 1106
 
1051  
-        self.where.add((alias, col, field, lookup_type, value), connector)
  1107
+        # To save memory and copying time, convert the value from the Python
  1108
+        # object to the actual value used in the SQL query.
  1109
+        if field:
  1110
+            params = field.get_db_prep_lookup(lookup_type, value)
  1111
+        else:
  1112
+            params = Field().get_db_prep_lookup(lookup_type, value)
  1113
+        if isinstance(value, datetime.datetime):
  1114
+            annotation = datetime.datetime
  1115
+        else:
  1116
+            annotation = bool(value)
  1117
+
  1118
+        self.where.add((alias, col, field.db_type(), lookup_type, annotation,
  1119
+            params), connector)
1052 1120
 
1053 1121
         if negate:
1054 1122
             for alias in join_list:
@@ -1058,7 +1126,8 @@ def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
1058 1126
                     for alias in join_list:
1059 1127
                         if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
1060 1128
                             j_col = self.alias_map[alias][RHS_JOIN_COL]
1061  
-                            entry = Node([(alias, j_col, None, 'isnull', True)])
  1129
+                            entry = Node([(alias, j_col, None, 'isnull', True,
  1130
+                                    [True])])
1062 1131
                             entry.negate()
1063 1132
                             self.where.add(entry, AND)
1064 1133
                             break
@@ -1066,7 +1135,7 @@ def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
1066 1135
                     # Leaky abstraction artifact: We have to specifically
1067 1136
                     # exclude the "foo__in=[]" case from this handling, because
1068 1137
                     # it's short-circuited in the Where class.
1069  
-                    entry = Node([(alias, col, field, 'isnull', True)])
  1138
+                    entry = Node([(alias, col, None, 'isnull', True, [True])])
1070 1139
                     entry.negate()
1071 1140
                     self.where.add(entry, AND)
1072 1141
 
@@ -1114,7 +1183,9 @@ def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True,
1114 1183
         (which gives the table we are joining to), 'alias' is the alias for the
1115 1184
         table we are joining to. If dupe_multis is True, any many-to-many or
1116 1185
         many-to-one joins will always create a new alias (necessary for
1117  
-        disjunctive filters).
  1186
+        disjunctive filters). If can_reuse is not None, it's a list of aliases
  1187
+        that can be reused in these joins (nothing else can be reused in this
  1188
+        case).
1118 1189
 
1119 1190
         Returns the final field involved in the join, the target database
1120 1191
         column (used for any 'where' constraint), the final 'opts' value and the
@@ -1122,7 +1193,14 @@ def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True,
1122 1193
         """
1123 1194
         joins = [alias]
1124 1195
         last = [0]
  1196
+        dupe_set = set()
  1197
+        exclusions = set()
1125 1198
         for pos, name in enumerate(names):
  1199
+            try:
  1200
+                exclusions.add(int_alias)
  1201
+            except NameError:
  1202
+                pass
  1203
+            exclusions.add(alias)
1126 1204
             last.append(len(joins))
1127 1205
             if name == 'pk':
1128 1206
                 name = opts.pk.name
@@ -1141,6 +1219,7 @@ def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True,
1141 1219
                     names = opts.get_all_field_names()
1142 1220
                     raise FieldError("Cannot resolve keyword %r into field. "
1143 1221
                             "Choices are: %s" % (name, ", ".join(names)))
  1222
+
1144 1223
             if not allow_many and (m2m or not direct):
1145 1224
                 for alias in joins: