Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #163 -- Added 'pk' database API option, which is a shorthand fo…

…r (primary_key)__exact

git-svn-id: http://code.djangoproject.com/svn/django/trunk@316 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 786c750c40417a59449f1c5595fcc6b370ca7d4f 1 parent f14c98e
Adrian Holovaty authored July 26, 2005
4  django/contrib/comments/models/comments.py
@@ -78,7 +78,7 @@ def get_content_object(self):
78 78
         """
79 79
         from django.core.exceptions import ObjectDoesNotExist
80 80
         try:
81  
-            return self.get_content_type().get_object_for_this_type(id__exact=self.object_id)
  81
+            return self.get_content_type().get_object_for_this_type(pk=self.object_id)
82 82
         except ObjectDoesNotExist:
83 83
             return None
84 84
 
@@ -193,7 +193,7 @@ def get_content_object(self):
193 193
         """
194 194
         from django.core.exceptions import ObjectDoesNotExist
195 195
         try:
196  
-            return self.get_content_type().get_object_for_this_type(id__exact=self.object_id)
  196
+            return self.get_content_type().get_object_for_this_type(pk=self.object_id)
197 197
         except ObjectDoesNotExist:
198 198
             return None
199 199
 
8  django/contrib/comments/templatetags/comments.py
@@ -80,7 +80,7 @@ def render(self, context):
80 80
             # We only have to do this validation if obj_id_lookup_var is provided,
81 81
             # because do_comment_form() validates hard-coded object IDs.
82 82
             try:
83  
-                self.content_type.get_object_for_this_type(id__exact=self.obj_id)
  83
+                self.content_type.get_object_for_this_type(pk=self.obj_id)
84 84
             except ObjectDoesNotExist:
85 85
                 context['display_form'] = False
86 86
             else:
@@ -203,7 +203,7 @@ def __call__(self, parser, token):
203 203
         if tokens[3].isdigit():
204 204
             obj_id = tokens[3]
205 205
             try: # ensure the object ID is valid
206  
-                content_type.get_object_for_this_type(id__exact=obj_id)
  206
+                content_type.get_object_for_this_type(pk=obj_id)
207 207
             except ObjectDoesNotExist:
208 208
                 raise template.TemplateSyntaxError, "'%s' tag refers to %s object with ID %s, which doesn't exist" % (self.tag_name, content_type.name, obj_id)
209 209
         else:
@@ -283,7 +283,7 @@ def __call__(self, parser, token):
283 283
         if tokens[3].isdigit():
284 284
             obj_id = tokens[3]
285 285
             try: # ensure the object ID is valid
286  
-                content_type.get_object_for_this_type(id__exact=obj_id)
  286
+                content_type.get_object_for_this_type(pk=obj_id)
287 287
             except ObjectDoesNotExist:
288 288
                 raise template.TemplateSyntaxError, "'%s' tag refers to %s object with ID %s, which doesn't exist" % (self.tag_name, content_type.name, obj_id)
289 289
         else:
@@ -338,7 +338,7 @@ def __call__(self, parser, token):
338 338
         if tokens[3].isdigit():
339 339
             obj_id = tokens[3]
340 340
             try: # ensure the object ID is valid
341  
-                content_type.get_object_for_this_type(id__exact=obj_id)
  341
+                content_type.get_object_for_this_type(pk=obj_id)
342 342
             except ObjectDoesNotExist:
343 343
                 raise template.TemplateSyntaxError, "'%s' tag refers to %s object with ID %s, which doesn't exist" % (self.tag_name, content_type.name, obj_id)
344 344
         else:
10  django/contrib/comments/views/comments.py
@@ -197,7 +197,7 @@ def post_comment(request):
197 197
         rating_range, rating_choices = [], []
198 198
     content_type_id, object_id = target.split(':') # target is something like '52:5157'
199 199
     try:
200  
-        obj = contenttypes.get_object(id__exact=content_type_id).get_object_for_this_type(id__exact=object_id)
  200
+        obj = contenttypes.get_object(pk=content_type_id).get_object_for_this_type(pk=object_id)
201 201
     except ObjectDoesNotExist:
202 202
         raise Http404, "The comment form had an invalid 'target' parameter -- the object ID was invalid"
203 203
     option_list = options.split(',') # options is something like 'pa,ra'
@@ -284,9 +284,9 @@ def post_free_comment(request):
284 284
     if comments.get_security_hash(options, '', '', target) != security_hash:
285 285
         raise Http404, "Somebody tampered with the comment form (security violation)"
286 286
     content_type_id, object_id = target.split(':') # target is something like '52:5157'
287  
-    content_type = contenttypes.get_object(id__exact=content_type_id)
  287
+    content_type = contenttypes.get_object(pk=content_type_id)
288 288
     try:
289  
-        obj = content_type.get_object_for_this_type(id__exact=object_id)
  289
+        obj = content_type.get_object_for_this_type(pk=object_id)
290 290
     except ObjectDoesNotExist:
291 291
         raise Http404, "The comment form had an invalid 'target' parameter -- the object ID was invalid"
292 292
     option_list = options.split(',')
@@ -336,8 +336,8 @@ def comment_was_posted(request):
336 336
     if request.GET.has_key('c'):
337 337
         content_type_id, object_id = request.GET['c'].split(':')
338 338
         try:
339  
-            content_type = contenttypes.get_object(id__exact=content_type_id)
340  
-            obj = content_type.get_object_for_this_type(id__exact=object_id)
  339
+            content_type = contenttypes.get_object(pk=content_type_id)
  340
+            obj = content_type.get_object_for_this_type(pk=object_id)
341 341
         except ObjectDoesNotExist:
342 342
             pass
343 343
     t = template_loader.get_template('comments/posted')
4  django/contrib/comments/views/karma.py
@@ -19,14 +19,14 @@ def vote(request, comment_id, vote):
19 19
     if request.user.is_anonymous():
20 20
         raise Http404, "Anonymous users cannot vote"
21 21
     try:
22  
-        comment = comments.get_object(id__exact=comment_id)
  22
+        comment = comments.get_object(pk=comment_id)
23 23
     except comments.CommentDoesNotExist:
24 24
         raise Http404, "Invalid comment ID"
25 25
     if comment.user_id == request.user.id:
26 26
         raise Http404, "No voting for yourself"
27 27
     karma.vote(request.user.id, comment_id, rating)
28 28
     # Reload comment to ensure we have up to date karma count
29  
-    comment = comments.get_object(id__exact=comment_id)
  29
+    comment = comments.get_object(pk=comment_id)
30 30
     t = template_loader.get_template('comments/karma_vote_accepted')
31 31
     c = Context(request, {
32 32
         'comment': comment
8  django/contrib/comments/views/userflags.py
@@ -16,7 +16,7 @@ def flag(request, comment_id):
16 16
             the flagged `comments.comments` object
17 17
     """
18 18
     try:
19  
-        comment = comments.get_object(id__exact=comment_id, site_id__exact=SITE_ID)
  19
+        comment = comments.get_object(pk=comment_id, site_id__exact=SITE_ID)
20 20
     except comments.CommentDoesNotExist:
21 21
         raise Http404
22 22
     if request.POST:
@@ -31,7 +31,7 @@ def flag(request, comment_id):
31 31
 
32 32
 def flag_done(request, comment_id):
33 33
     try:
34  
-        comment = comments.get_object(id__exact=comment_id, site_id__exact=SITE_ID)
  34
+        comment = comments.get_object(pk=comment_id, site_id__exact=SITE_ID)
35 35
     except comments.CommentDoesNotExist:
36 36
         raise Http404
37 37
     t = template_loader.get_template('comments/flag_done')
@@ -50,7 +50,7 @@ def delete(request, comment_id):
50 50
             the flagged `comments.comments` object
51 51
     """
52 52
     try:
53  
-        comment = comments.get_object(id__exact=comment_id, site_id__exact=SITE_ID)
  53
+        comment = comments.get_object(pk=comment_id, site_id__exact=SITE_ID)
54 54
     except comments.CommentDoesNotExist:
55 55
         raise Http404
56 56
     if not comments.user_is_moderator(request.user):
@@ -72,7 +72,7 @@ def delete(request, comment_id):
72 72
 
73 73
 def delete_done(request, comment_id):
74 74
     try:
75  
-        comment = comments.get_object(id__exact=comment_id, site_id__exact=SITE_ID)
  75
+        comment = comments.get_object(pk=comment_id, site_id__exact=SITE_ID)
76 76
     except comments.CommentDoesNotExist:
77 77
         raise Http404
78 78
     t = template_loader.get_template('comments/delete_done')
3  django/core/meta.py
@@ -1146,6 +1146,9 @@ def _parse_lookup(kwarg_items, opts, table_count=0):
1146 1146
                 params.extend(params2)
1147 1147
             continue
1148 1148
         lookup_list = kwarg.split(LOOKUP_SEPARATOR)
  1149
+        # pk="value" is shorthand for (primary key)__exact="value"
  1150
+        if lookup_list[-1] == 'pk':
  1151
+            lookup_list = lookup_list[:-1] + [opts.pk.name, 'exact']
1149 1152
         if len(lookup_list) == 1:
1150 1153
             _throw_bad_kwarg_error(kwarg)
1151 1154
         lookup_type = lookup_list.pop()
4  django/models/auth.py
@@ -222,7 +222,7 @@ def _module_start_web_session(user_id, request, response):
222 222
         "Sets the necessary cookie in the given HttpResponse object, also updates last login time for user."
223 223
         from django.models.auth import users
224 224
         from django.conf.settings import REGISTRATION_COOKIE_DOMAIN
225  
-        user = users.get_object(id__exact=user_id)
  225
+        user = users.get_object(pk=user_id)
226 226
         user.last_login = datetime.datetime.now()
227 227
         user.save()
228 228
         session = create_session(user_id)
@@ -274,7 +274,7 @@ def is_deletion(self):
274 274
 
275 275
     def get_edited_object(self):
276 276
         "Returns the edited object represented by this log entry"
277  
-        return self.get_content_type().get_object_for_this_type(id__exact=self.object_id)
  277
+        return self.get_content_type().get_object_for_this_type(pk=self.object_id)
278 278
 
279 279
     def get_admin_url(self):
280 280
         """
2  django/models/core.py
@@ -14,7 +14,7 @@ def __repr__(self):
14 14
     def _module_get_current():
15 15
         "Returns the current site, according to the SITE_ID constant."
16 16
         from django.conf.settings import SITE_ID
17  
-        return get_object(id__exact=SITE_ID)
  17
+        return get_object(pk=SITE_ID)
18 18
 
19 19
 class Package(meta.Model):
20 20
     db_table = 'packages'
6  django/views/admin/doc.py
... ...
@@ -1,6 +1,3 @@
1  
-import os
2  
-import re
3  
-import inspect
4 1
 from django.core import meta
5 2
 from django import templatetags
6 3
 from django.conf import settings
@@ -14,6 +11,7 @@
14 11
     from django.parts.admin import doc
15 12
 except ImportError:
16 13
     doc = None
  14
+import inspect, os, re
17 15
 
18 16
 # Exclude methods starting with these strings from documentation
19 17
 MODEL_METHODS_EXCLUDE = ('_', 'add_', 'delete', 'save', 'set_')
@@ -128,7 +126,7 @@ def view_index(request):
128 126
                 'module' : func.__module__,
129 127
                 'title'  : title,
130 128
                 'site_id': settings_mod.SITE_ID,
131  
-                'site'   : sites.get_object(id__exact=settings_mod.SITE_ID),
  129
+                'site'   : sites.get_object(pk=settings_mod.SITE_ID),
132 130
                 'url'    : simplify_regex(regex),
133 131
             })
134 132
     t = template_loader.get_template('doc/view_index')
4  django/views/defaults.py
@@ -7,8 +7,8 @@
7 7
 def shortcut(request, content_type_id, object_id):
8 8
     from django.models.core import contenttypes
9 9
     try:
10  
-        content_type = contenttypes.get_object(id__exact=content_type_id)
11  
-        obj = content_type.get_object_for_this_type(id__exact=object_id)
  10
+        content_type = contenttypes.get_object(pk=content_type_id)
  11
+        obj = content_type.get_object_for_this_type(pk=object_id)
12 12
     except ObjectDoesNotExist:
13 13
         raise Http404, "Content type %s object %s doesn't exist" % (content_type_id, object_id)
14 14
     if not hasattr(obj, 'get_absolute_url'):
13  docs/db-api.txt
@@ -97,6 +97,19 @@ Multiple lookups are allowed, of course, and are translated as "AND"s::
97 97
 
98 98
 ...retrieves all polls published in January 2005 that have a question starting with "Would."
99 99
 
  100
+For convenience, there's a ``pk`` lookup type, which translates into
  101
+``(primary_key)__exact``. In the polls example, these two statements are
  102
+equivalent::
  103
+
  104
+    polls.get_object(id__exact=3)
  105
+    polls.get_object(pk=3)
  106
+
  107
+``pk`` lookups also work across joins. In the polls example, these two
  108
+statements are equivalent::
  109
+
  110
+    choices.get_list(poll__id__exact=3)
  111
+    choices.get_list(poll__pk=3)
  112
+
100 113
 Ordering
101 114
 ========
102 115
 
8  docs/overview.txt
@@ -93,6 +93,12 @@ is created on the fly: No code generation necessary::
93 93
         ...
94 94
     django.models.news.ReporterDoesNotExist: Reporter does not exist for {'id__exact': 2}
95 95
 
  96
+    # Lookup by a primary key is the most common case, so Django provides a
  97
+    # shortcut for primary-key exact lookups.
  98
+    # The following is identical to reporters.get_object(id__exact=1).
  99
+    >>> reporters.get_object(pk=1)
  100
+    John Smith
  101
+
96 102
     # Create an article.
97 103
     >>> from datetime import datetime
98 104
     >>> a = articles.Article(id=None, pub_date=datetime.now(), headline='Django is cool', article='Yeah.', reporter_id=1)
@@ -200,7 +206,7 @@ article_detail from above::
200 206
     def article_detail(request, year, month, article_id):
201 207
         # Use the Django API to find an object matching the URL criteria.
202 208
         try:
203  
-            a = articles.get_object(pub_date__year=year, pub_date__month=month, id__exact=article_id)
  209
+            a = articles.get_object(pub_date__year=year, pub_date__month=month, pk=article_id)
204 210
         except articles.ArticleDoesNotExist:
205 211
             raise Http404
206 212
         t = template_loader.get_template('news/article_detail')
34  docs/tutorial01.txt
@@ -49,10 +49,10 @@ settings. Let's look at what ``startproject`` created::
49 49
 First, edit ``myproject/settings/main.py``. It's a normal Python module with
50 50
 module-level variables representing Django settings. Edit the file and change
51 51
 these settings to match your database's connection parameters:
52  
-    
53  
-    * ``DATABASE_ENGINE`` -- Either 'postgresql', 'mysql' or 'sqlite3'. 
  52
+
  53
+    * ``DATABASE_ENGINE`` -- Either 'postgresql', 'mysql' or 'sqlite3'.
54 54
       More coming soon.
55  
-    * ``DATABASE_NAME`` -- The name of your database, or the full path to 
  55
+    * ``DATABASE_NAME`` -- The name of your database, or the full path to
56 56
       the database file if using sqlite.
57 57
     * ``DATABASE_USER`` -- Your database username (not used for sqlite).
58 58
     * ``DATABASE_PASSWORD`` -- Your database password (not used for sqlite).
@@ -134,7 +134,7 @@ The first step in writing a database Web app in Django is to define your models
134 134
 -- essentially, your database layout, with additional metadata.
135 135
 
136 136
 .. admonition:: Philosophy
137  
-   
  137
+
138 138
    A model is the single, definitive source of data about your
139 139
    data. It contains the essential fields and behaviors of the data you're
140 140
    storing. Django follows the `DRY Principle`_. The goal is to define your
@@ -243,11 +243,11 @@ Note the following:
243 243
     * Table names are automatically generated by combining the name of the app
244 244
       (polls) with a plural version of the object name (polls and choices). (You
245 245
       can override this behavior.)
246  
-      
  246
+
247 247
     * Primary keys (IDs) are added automatically. (You can override this, too.)
248  
-    
  248
+
249 249
     * The foreign key relationship is made explicit by a ``REFERENCES`` statement.
250  
-    
  250
+
251 251
     * It's tailored to the database you're using, so database-specific field types
252 252
       such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or ``integer
253 253
       primary key`` (SQLite) are handled for you automatically. The author of
@@ -256,16 +256,16 @@ Note the following:
256 256
 
257 257
 If you're interested, also run the following commands:
258 258
 
259  
-    * ``django-admin.py sqlinitialdata polls`` -- Outputs the initial-data 
  259
+    * ``django-admin.py sqlinitialdata polls`` -- Outputs the initial-data
260 260
       inserts required for Django's admin framework.
261  
-    
262  
-    * ``django-admin.py sqlclear polls`` -- Outputs the necessary ``DROP 
  261
+
  262
+    * ``django-admin.py sqlclear polls`` -- Outputs the necessary ``DROP
263 263
       TABLE`` statements for this app, according to which tables already exist
264 264
       in your database (if any).
265  
-      
  265
+
266 266
     * ``django-admin.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
267 267
       statements for this app.
268  
-    
  268
+
269 269
     * ``django-admin.py sqlall polls`` -- A combination of 'sql' and
270 270
       'sqlinitialdata'.
271 271
 
@@ -372,14 +372,20 @@ Let's jump back into the Python interactive shell::
372 372
     >>> polls.get_list(question__startswith='What')
373 373
     [What's up]
374 374
 
  375
+    # Lookup by a primary key is the most common case, so Django provides a
  376
+    # shortcut for primary-key exact lookups.
  377
+    # The following is identical to polls.get_object(id__exact=1).
  378
+    >>> polls.get_object(pk=1)
  379
+    What's up
  380
+
375 381
     # Make sure our custom method worked.
376  
-    >>> p = polls.get_object(id__exact=1)
  382
+    >>> p = polls.get_object(pk=1)
377 383
     >>> p.was_published_today()
378 384
     False
379 385
 
380 386
     # Give the Poll a couple of Choices. Each one of these method calls does an
381 387
     # INSERT statement behind the scenes and returns the new Choice object.
382  
-    >>> p = polls.get_object(id__exact=1)
  388
+    >>> p = polls.get_object(pk=1)
383 389
     >>> p.add_choice(choice='Not much', votes=0)
384 390
     Not much
385 391
     >>> p.add_choice(choice='The sky', votes=0)
2  docs/tutorial03.txt
@@ -242,7 +242,7 @@ for a given poll. Here's the view::
242 242
     from django.core.exceptions import Http404
243 243
     def detail(request, poll_id):
244 244
         try:
245  
-            p = polls.get_object(id__exact=poll_id)
  245
+            p = polls.get_object(pk=poll_id)
246 246
         except polls.PollDoesNotExist:
247 247
             raise Http404
248 248
         t = template_loader.get_template('polls/detail')

0 notes on commit 786c750

Please sign in to comment.
Something went wrong with that request. Please try again.