Changeset 3246
- Timestamp:
- 06/30/06 20:14:41 (3 years ago)
- Files:
-
- django/trunk/django/db/models/fields/related.py (modified) (1 diff)
- django/trunk/django/db/models/query.py (modified) (2 diffs)
- django/trunk/django/db/models/related.py (modified) (1 diff)
- django/trunk/tests/modeltests/many_to_many/models.py (modified) (3 diffs)
- django/trunk/tests/modeltests/many_to_one/models.py (modified) (4 diffs)
- django/trunk/tests/modeltests/one_to_one/models.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/db/models/fields/related.py
r3197 r3246 79 79 self.contribute_to_related_class(other, related) 80 80 81 def get_db_prep_lookup(self, lookup_type, value): 82 # If we are doing a lookup on a Related Field, we must be 83 # comparing object instances. The value should be the PK of value, 84 # not value itself. 85 def pk_trace(value): 86 # Value may be a primary key, or an object held in a relation. 87 # If it is an object, then we need to get the primary key value for 88 # that object. In certain conditions (especially one-to-one relations), 89 # the primary key may itself be an object - so we need to keep drilling 90 # down until we hit a value that can be used for a comparison. 91 v = value 92 try: 93 while True: 94 v = getattr(v, v._meta.pk.name) 95 except AttributeError: 96 pass 97 return v 98 99 if lookup_type == 'exact': 100 return [pk_trace(value)] 101 if lookup_type == 'in': 102 return [pk_trace(v) for v in value] 103 elif lookup_type == 'isnull': 104 return [] 105 raise TypeError, "Related Field has invalid lookup: %s" % lookup_type 106 81 107 def _get_related_query_name(self, opts): 82 108 # This method defines the name that can be used to identify this related object django/trunk/django/db/models/query.py
r3217 r3246 842 842 843 843 if path: 844 # There are elements left in the path. More joins are required. 844 845 if len(path) == 1 and path[0] in (new_opts.pk.name, None) \ 845 846 and clause in ('exact', 'isnull') and not join_required: 846 # If the last name query is for a key, and the search is for 847 # isnull/exact, then the current (for N-1) or intermediate 848 # (for N-N) table can be used for the search - no need to join an 849 # extra table just to check the primary key. 847 # If the next and final name query is for a primary key, 848 # and the search is for isnull/exact, then the current 849 # (for N-1) or intermediate (for N-N) table can be used 850 # for the search - no need to join an extra table just 851 # to check the primary key. 850 852 new_table = current_table 851 853 else: … … 873 875 params.extend(params2) 874 876 else: 875 # Evaluate clause on current table. 876 if name in (current_opts.pk.name, None) and clause in ('exact', 'isnull') and current_column: 877 # If this is an exact/isnull key search, and the last pass 878 # found/introduced a current/intermediate table that we can use to 879 # optimize the query, then use that column name. 877 # No elements left in path. Current element is the element on which 878 # the search is being performed. 879 880 if join_required: 881 # Last query term is a RelatedObject 882 if field.field.rel.multiple: 883 # RelatedObject is from a 1-N relation. 884 # Join is required; query operates on joined table. 885 column = new_opts.pk.name 886 joins[backend.quote_name(new_table)] = ( 887 backend.quote_name(new_opts.db_table), 888 "INNER JOIN", 889 "%s.%s = %s.%s" % 890 (backend.quote_name(current_table), 891 backend.quote_name(join_column), 892 backend.quote_name(new_table), 893 backend.quote_name(new_column)) 894 ) 895 current_table = new_table 896 else: 897 # RelatedObject is from a 1-1 relation, 898 # No need to join; get the pk value from the related object, 899 # and compare using that. 900 column = current_opts.pk.name 901 elif intermediate_table: 902 # Last query term is a related object from an N-N relation. 903 # Join from intermediate table is sufficient. 904 column = join_column 905 elif name == current_opts.pk.name and clause in ('exact', 'isnull') and current_column: 906 # Last query term is for a primary key. If previous iterations 907 # introduced a current/intermediate table that can be used to 908 # optimize the query, then use that table and column name. 880 909 column = current_column 881 910 else: 911 # Last query term was a normal field. 882 912 column = field.column 883 913 django/trunk/django/db/models/related.py
r2809 r3246 71 71 return [None] * self.field.rel.num_in_admin 72 72 73 def get_db_prep_lookup(self, lookup_type, value): 74 # Defer to the actual field definition for db prep 75 return self.field.get_db_prep_lookup(lookup_type, value) 76 73 77 def editable_fields(self): 74 78 "Get the fields in this class that should be edited inline." django/trunk/tests/modeltests/many_to_many/models.py
r3075 r3246 76 76 >>> Article.objects.filter(publications__pk=1) 77 77 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 78 >>> Article.objects.filter(publications=1) 79 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 80 >>> Article.objects.filter(publications=p1) 81 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 78 82 79 83 >>> Article.objects.filter(publications__title__startswith="Science") … … 90 94 1 91 95 96 >>> Article.objects.filter(publications__in=[1,2]).distinct() 97 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 98 >>> Article.objects.filter(publications__in=[1,p2]).distinct() 99 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 100 >>> Article.objects.filter(publications__in=[p1,p2]).distinct() 101 [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>] 102 92 103 # Reverse m2m queries are supported (i.e., starting at the table that doesn't 93 104 # have a ManyToManyField). … … 102 113 >>> Publication.objects.filter(article__id__exact=1) 103 114 [<Publication: The Python Journal>] 104 105 115 >>> Publication.objects.filter(article__pk=1) 106 116 [<Publication: The Python Journal>] 117 >>> Publication.objects.filter(article=1) 118 [<Publication: The Python Journal>] 119 >>> Publication.objects.filter(article=a1) 120 [<Publication: The Python Journal>] 121 122 >>> Publication.objects.filter(article__in=[1,2]).distinct() 123 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 124 >>> Publication.objects.filter(article__in=[1,a2]).distinct() 125 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 126 >>> Publication.objects.filter(article__in=[a1,a2]).distinct() 127 [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>] 107 128 108 129 # If we delete a Publication, its Articles won't be able to access it. django/trunk/tests/modeltests/many_to_one/models.py
r3075 r3246 152 152 153 153 # Find all Articles for the Reporter whose ID is 1. 154 # Use direct ID check, pk check, and object comparison 154 155 >>> Article.objects.filter(reporter__id__exact=1) 155 156 [<Article: John's second story>, <Article: This is a test>] 156 157 >>> Article.objects.filter(reporter__pk=1) 157 158 [<Article: John's second story>, <Article: This is a test>] 159 >>> Article.objects.filter(reporter=1) 160 [<Article: John's second story>, <Article: This is a test>] 161 >>> Article.objects.filter(reporter=r) 162 [<Article: John's second story>, <Article: This is a test>] 163 164 >>> Article.objects.filter(reporter__in=[1,2]).distinct() 165 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] 166 >>> Article.objects.filter(reporter__in=[r,r2]).distinct() 167 [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>] 158 168 159 169 # You need two underscores between "reporter" and "id" -- not one. … … 169 179 TypeError: Cannot resolve keyword 'reporter_id' into field 170 180 171 # "pk" shortcut syntax works in a related context, too.172 >>> Article.objects.filter(reporter__pk=1)173 [<Article: John's second story>, <Article: This is a test>]174 175 181 # You can also instantiate an Article by passing 176 182 # the Reporter's ID instead of a Reporter object. … … 201 207 >>> Reporter.objects.filter(article__pk=1) 202 208 [<Reporter: John Smith>] 209 >>> Reporter.objects.filter(article=1) 210 [<Reporter: John Smith>] 211 >>> Reporter.objects.filter(article=a) 212 [<Reporter: John Smith>] 213 214 >>> Reporter.objects.filter(article__in=[1,4]).distinct() 215 [<Reporter: John Smith>] 216 >>> Reporter.objects.filter(article__in=[1,a3]).distinct() 217 [<Reporter: John Smith>] 218 >>> Reporter.objects.filter(article__in=[a,a3]).distinct() 219 [<Reporter: John Smith>] 220 203 221 >>> Reporter.objects.filter(article__headline__startswith='This') 204 222 [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>] … … 216 234 [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>] 217 235 >>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct() 236 [<Reporter: John Smith>] 237 >>> Reporter.objects.filter(article__reporter__exact=r).distinct() 218 238 [<Reporter: John Smith>] 219 239 django/trunk/tests/modeltests/one_to_one/models.py
r3075 r3246 95 95 >>> Restaurant.objects.get(place__exact=1) 96 96 <Restaurant: Demon Dogs the restaurant> 97 >>> Restaurant.objects.get(place__exact=p1) 98 <Restaurant: Demon Dogs the restaurant> 99 >>> Restaurant.objects.get(place=1) 100 <Restaurant: Demon Dogs the restaurant> 101 >>> Restaurant.objects.get(place=p1) 102 <Restaurant: Demon Dogs the restaurant> 97 103 >>> Restaurant.objects.get(place__pk=1) 98 104 <Restaurant: Demon Dogs the restaurant> … … 106 112 >>> Place.objects.get(restaurant__place__exact=1) 107 113 <Place: Demon Dogs the place> 114 >>> Place.objects.get(restaurant__place__exact=p1) 115 <Place: Demon Dogs the place> 108 116 >>> Place.objects.get(restaurant__pk=1) 117 <Place: Demon Dogs the place> 118 >>> Place.objects.get(restaurant=1) 119 <Place: Demon Dogs the place> 120 >>> Place.objects.get(restaurant=r) 121 <Place: Demon Dogs the place> 122 >>> Place.objects.get(restaurant__exact=1) 123 <Place: Demon Dogs the place> 124 >>> Place.objects.get(restaurant__exact=r) 109 125 <Place: Demon Dogs the place> 110 126 … … 116 132 117 133 # Query the waiters 134 >>> Waiter.objects.filter(restaurant__place__pk=1) 135 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 118 136 >>> Waiter.objects.filter(restaurant__place__exact=1) 137 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 138 >>> Waiter.objects.filter(restaurant__place__exact=p1) 119 139 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 120 140 >>> Waiter.objects.filter(restaurant__pk=1) … … 124 144 >>> Waiter.objects.filter(pk=1) 125 145 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 146 >>> Waiter.objects.filter(restaurant=1) 147 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 148 >>> Waiter.objects.filter(restaurant=r) 149 [<Waiter: Joe the waiter at Demon Dogs the restaurant>] 126 150 127 151 # Delete the restaurant; the waiter should also be removed
