Django

Code

Changeset 7791

Show
Ignore:
Timestamp:
06/30/08 01:24:21 (2 months ago)
Author:
mtredinnick
Message:

Fixed #7314 -- Changed the way extra() bits are handled when QuerySets? are merged.

Also added a section to the documentation to indicate why it's probably not a
good idea to rely on this feature for complex stuff. Garbage in, garbage out
applies even to Django code.

Thanks to erik for the test case for this one.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/db/models/sql/query.py

    r7788 r7791  
    367367                self.select.append(item) 
    368368        self.select_fields = rhs.select_fields[:] 
    369         self.extra_select = rhs.extra_select.copy() 
    370         self.extra_tables = rhs.extra_tables 
    371         self.extra_where = rhs.extra_where 
    372         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 
    373384 
    374385        # Ordering uses the 'rhs' ordering, unless it has none, in which case 
  • django/trunk/docs/db-api.txt

    r7745 r7791  
    443443Note, however, that the first of these will raise ``IndexError`` while the 
    444444second will raise ``DoesNotExist`` if no objects match the given criteria. 
     445 
     446Combining QuerySets 
     447------------------- 
     448 
     449If you have two ``QuerySet`` instances that act on the same model, you can 
     450combine them using ``&`` and ``|`` to get the items that are in both result 
     451sets or in either results set, respectively. For example:: 
     452 
     453    Entry.objects.filter(pubdate__gte=date1) & \ 
     454            Entry.objects.filter(headline__startswith="What") 
     455 
     456will combine the two queries into a single SQL query. Of course, in this case 
     457you could have achieved the same result using multiple filters on the same 
     458``QuerySet``, but sometimes the ability to combine individual ``QuerySet`` 
     459instance is useful. 
     460 
     461Be careful, if you are using ``extra()`` to add custom handling to your 
     462``QuerySet`` however. All the ``extra()`` components are merged and the result 
     463may or may not make sense. If you are using custom SQL fragments in your 
     464``extra()`` calls, Django will not inspect these fragments to see if they need 
     465to be rewritten because of changes in the merged query. So test the effects 
     466carefully. Also realise that if you are combining two ``QuerySets`` with 
     467``|``, you cannot use ``extra(select=...)`` or ``extra(where=...)`` on *both* 
     468``QuerySets``. You can only use those calls on one or the other (Django will 
     469raise a ``ValueError`` if you try to use this incorrectly). 
    445470 
    446471QuerySet methods that return new QuerySets