Changeset 7230
- Timestamp:
- 03/12/08 07:41:58 (6 months ago)
- Files:
-
- django/branches/queryset-refactor/django/db/models/query.py (modified) (1 diff)
- django/branches/queryset-refactor/django/db/models/sql/query.py (modified) (3 diffs)
- django/branches/queryset-refactor/django/db/models/sql/subqueries.py (modified) (1 diff)
- django/branches/queryset-refactor/docs/db-api.txt (modified) (1 diff)
- django/branches/queryset-refactor/tests/modeltests/many_to_one/models.py (modified) (1 diff)
- django/branches/queryset-refactor/tests/modeltests/model_inheritance/models.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/queryset-refactor/django/db/models/query.py
r7169 r7230 479 479 def _setup_query(self): 480 480 """ 481 Sets up any special features of the query attribute. 481 Constructs the field_names list that the values query will be 482 retrieving. 482 483 483 484 Called by the _clone() method after initialising the rest of the 484 485 instance. 485 486 """ 486 # Construct two objects:487 # - fields is a list of Field objects to fetch.488 # - field_names is a list of field names, which will be the keys in489 # the resulting dictionaries.490 # 'fields' is used to configure the query, whilst field_names is stored491 # in this object for use by iterator().492 487 if self._fields: 493 opts = self.model._meta494 all = dict([(field.column, field) for field in opts.fields])495 for field in opts.fields:496 all[field.name] = field497 488 if not self.query.extra_select: 498 try:499 fields = [all[f] for f in self._fields]500 except KeyError, e:501 raise FieldDoesNotExist('%s has no field named %r'502 % (opts.object_name, e.args[0]))503 489 field_names = list(self._fields) 504 490 else: 505 fields = []506 491 field_names = [] 492 names = set(self.model._meta.get_all_field_names()) 507 493 for f in self._fields: 508 if f in all: 509 fields.append(all[f]) 494 if f in names: 510 495 field_names.append(f) 511 496 elif not self.query.extra_select.has_key(f): 512 497 raise FieldDoesNotExist('%s has no field named %r' 513 498 % (self.model._meta.object_name, f)) 514 else: # Default to all fields.515 fields = self.model._meta.fields516 field_names = [f.attname for f in fields]517 518 self.query.add_ local_columns([f.column for f in fields])499 else: 500 # Default to all fields. 501 field_names = [f.attname for f in self.model._meta.fields] 502 503 self.query.add_fields(field_names) 519 504 self.query.default_cols = False 520 505 self.field_names = field_names django/branches/queryset-refactor/django/db/models/sql/query.py
r7224 r7230 917 917 self.where.end_subtree() 918 918 919 def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True): 919 def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True, 920 allow_explicit_fk=False): 920 921 """ 921 922 Compute the necessary table joins for the passage through the fields … … 940 941 field, model, direct, m2m = opts.get_field_by_name(name) 941 942 except FieldDoesNotExist: 942 names = opts.get_all_field_names() 943 raise FieldError("Cannot resolve keyword %r into field. " 944 "Choices are: %s" % (name, ", ".join(names))) 943 for f in opts.fields: 944 if allow_explicit_fk and name == f.attname: 945 # XXX: A hack to allow foo_id to work in values() for 946 # backwards compatibility purposes. If we dropped that 947 # feature, this could be removed. 948 field, model, direct, m2m = opts.get_field_by_name(f.name) 949 break 950 else: 951 names = opts.get_all_field_names() 952 raise FieldError("Cannot resolve keyword %r into field. " 953 "Choices are: %s" % (name, ", ".join(names))) 945 954 if not allow_many and (m2m or not direct): 946 955 for join in joins: … … 1103 1112 return not (self.low_mark or self.high_mark) 1104 1113 1105 def add_ local_columns(self, columns):1106 """ 1107 Adds the given column names to the select set, assuming they come from1108 the root model (the one given in self.model).1109 """ 1110 for alias in self.tables:1111 if self.alias_map[alias][ALIAS_REFCOUNT]:1112 break1113 else:1114 alias = self.get_initial_alias()1115 self.select.extend([(alias, col) for col in columns])1114 def add_fields(self, field_names): 1115 """ 1116 Adds the given (model) fields to the select set. The field names are 1117 added in the order specified. 1118 """ 1119 alias = self.get_initial_alias() 1120 opts = self.get_meta() 1121 for name in field_names: 1122 u1, target, u2, joins = self.setup_joins(name.split(LOOKUP_SEP), 1123 opts, alias, False, False, True) 1124 self.select.append((joins[-1][-1], target.column)) 1116 1125 1117 1126 def add_ordering(self, *ordering): django/branches/queryset-refactor/django/db/models/sql/subqueries.py
r7190 r7230 161 161 alias = '%s0' % self.alias_prefix 162 162 query.change_alias(query.tables[0], alias) 163 self.add_ local_columns([query.model._meta.pk.column])163 self.add_fields([query.model._meta.pk.name]) 164 164 165 165 # Now we adjust the current query: reset the where clause and get rid django/branches/queryset-refactor/docs/db-api.txt
r7221 r7230 596 596 >>> Blog.objects.values('id', 'name') 597 597 [{'id': 1, 'name': 'Beatles Blog'}] 598 599 You can also retrieve values from across ``ForeignKey`` relations by using 600 double underscores to separate the field names, just as when calling the 601 ``filter()`` command. For example:: 602 603 >>> Entry.objects.values('blog__name').distinct() 604 [{'name': 'Beatles Blog'}] 598 605 599 606 A couple of subtleties that are worth mentioning: django/branches/queryset-refactor/tests/modeltests/many_to_one/models.py
r7163 r7230 250 250 >>> Reporter.objects.filter(article__reporter=r).distinct() 251 251 [<Reporter: John Smith>] 252 253 # It's possible to use values() calls across many-to-one relations. 254 >>> d = {'reporter__first_name': u'John', 'reporter__last_name': u'Smith'} 255 >>> list(Article.objects.filter(reporter=r).distinct().values('reporter__first_name', 'reporter__last_name')) == [d] 256 True 252 257 253 258 # If you delete a reporter, his articles will be deleted. django/branches/queryset-refactor/tests/modeltests/model_inheritance/models.py
r7218 r7230 15 15 from django.db import models 16 16 17 # 18 # Abstract base classes 19 # 20 17 21 class CommonInfo(models.Model): 18 22 name = models.CharField(max_length=50) … … 34 38 class Meta: 35 39 pass 40 41 # 42 # Multi-table inheritance 43 # 36 44 37 45 class Place(models.Model): … … 228 236 u'Demon Puppies' 229 237 238 # The values() command also works on fields from parent models. 239 >>> d = {'rating': 4, 'name': u'Ristorante Miron'} 240 >>> list(ItalianRestaurant.objects.values('name', 'rating')) == [d] 241 True 242 230 243 """}
