mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
gis: Merged revisions 7485-7491,7493-7497 via svnmerge from trunk.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7498 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a125a1c9b6
commit
e5b52f90f0
@ -716,24 +716,9 @@ class ChangeList(object):
|
|||||||
qs = qs.select_related()
|
qs = qs.select_related()
|
||||||
break
|
break
|
||||||
|
|
||||||
# Calculate lookup_order_field.
|
|
||||||
# If the order-by field is a field with a relationship, order by the
|
|
||||||
# value in the related table.
|
|
||||||
lookup_order_field = self.order_field
|
|
||||||
try:
|
|
||||||
f = self.lookup_opts.get_field(self.order_field, many_to_many=False)
|
|
||||||
except models.FieldDoesNotExist:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if isinstance(f.rel, models.OneToOneRel):
|
|
||||||
# For OneToOneFields, don't try to order by the related object's ordering criteria.
|
|
||||||
pass
|
|
||||||
elif isinstance(f.rel, models.ManyToOneRel):
|
|
||||||
rel_ordering = f.rel.to._meta.ordering and f.rel.to._meta.ordering[0] or f.rel.to._meta.pk.column
|
|
||||||
lookup_order_field = '%s.%s' % (f.rel.to._meta.db_table, rel_ordering)
|
|
||||||
|
|
||||||
# Set ordering.
|
# Set ordering.
|
||||||
qs = qs.order_by((self.order_type == 'desc' and '-' or '') + lookup_order_field)
|
if self.order_field:
|
||||||
|
qs = qs.order_by('%s%s' % ((self.order_type == 'desc' and '-' or ''), self.order_field))
|
||||||
|
|
||||||
# Apply keyword searches.
|
# Apply keyword searches.
|
||||||
def construct_search(field_name):
|
def construct_search(field_name):
|
||||||
|
@ -51,6 +51,7 @@ class BaseDatabaseFeatures(object):
|
|||||||
uses_case_insensitive_names = False
|
uses_case_insensitive_names = False
|
||||||
uses_custom_query_class = False
|
uses_custom_query_class = False
|
||||||
empty_fetchmany_value = []
|
empty_fetchmany_value = []
|
||||||
|
update_can_self_select = True
|
||||||
|
|
||||||
class BaseDatabaseOperations(object):
|
class BaseDatabaseOperations(object):
|
||||||
"""
|
"""
|
||||||
|
@ -63,6 +63,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||||||
autoindexes_primary_keys = False
|
autoindexes_primary_keys = False
|
||||||
inline_fk_references = False
|
inline_fk_references = False
|
||||||
empty_fetchmany_value = ()
|
empty_fetchmany_value = ()
|
||||||
|
update_can_self_select = False
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def date_extract_sql(self, lookup_type, field_name):
|
def date_extract_sql(self, lookup_type, field_name):
|
||||||
|
@ -67,6 +67,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||||||
autoindexes_primary_keys = False
|
autoindexes_primary_keys = False
|
||||||
inline_fk_references = False
|
inline_fk_references = False
|
||||||
empty_fetchmany_value = ()
|
empty_fetchmany_value = ()
|
||||||
|
update_can_self_select = False
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def date_extract_sql(self, lookup_type, field_name):
|
def date_extract_sql(self, lookup_type, field_name):
|
||||||
|
@ -9,6 +9,7 @@ except ImportError:
|
|||||||
|
|
||||||
from django.db import get_creation_module
|
from django.db import get_creation_module
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
|
from django.db.models.query_utils import QueryWrapper
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
@ -226,6 +227,9 @@ class Field(object):
|
|||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
"Returns field's value prepared for database lookup."
|
"Returns field's value prepared for database lookup."
|
||||||
|
if hasattr(value, 'as_sql'):
|
||||||
|
sql, params = value.as_sql()
|
||||||
|
return QueryWrapper(('(%s)' % sql), params)
|
||||||
if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'):
|
if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'):
|
||||||
return [value]
|
return [value]
|
||||||
elif lookup_type in ('range', 'in'):
|
elif lookup_type in ('range', 'in'):
|
||||||
|
@ -284,6 +284,7 @@ class QuerySet(object):
|
|||||||
query = self.query.clone(sql.UpdateQuery)
|
query = self.query.clone(sql.UpdateQuery)
|
||||||
query.add_update_values(kwargs)
|
query.add_update_values(kwargs)
|
||||||
query.execute_sql(None)
|
query.execute_sql(None)
|
||||||
|
transaction.commit_unless_managed()
|
||||||
self._result_cache = None
|
self._result_cache = None
|
||||||
update.alters_data = True
|
update.alters_data = True
|
||||||
|
|
||||||
@ -496,9 +497,6 @@ class ValuesQuerySet(QuerySet):
|
|||||||
# QuerySet.clone() will also set up the _fields attribute with the
|
# QuerySet.clone() will also set up the _fields attribute with the
|
||||||
# names of the model fields to select.
|
# names of the model fields to select.
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self.iterator()
|
|
||||||
|
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
self.query.trim_extra_select(self.extra_names)
|
self.query.trim_extra_select(self.extra_names)
|
||||||
names = self.query.extra_select.keys() + self.field_names
|
names = self.query.extra_select.keys() + self.field_names
|
||||||
|
@ -28,7 +28,7 @@ NULLABLE = 6
|
|||||||
MULTI = 'multi'
|
MULTI = 'multi'
|
||||||
SINGLE = 'single'
|
SINGLE = 'single'
|
||||||
|
|
||||||
ORDER_PATTERN = re.compile(r'\?|[-+]?\w+$')
|
ORDER_PATTERN = re.compile(r'\?|[-+]?[.\w]+$')
|
||||||
ORDER_DIR = {
|
ORDER_DIR = {
|
||||||
'ASC': ('ASC', 'DESC'),
|
'ASC': ('ASC', 'DESC'),
|
||||||
'DESC': ('DESC', 'ASC')}
|
'DESC': ('DESC', 'ASC')}
|
||||||
|
@ -895,9 +895,15 @@ class Query(object):
|
|||||||
Add a single filter to the query. The 'filter_expr' is a pair:
|
Add a single filter to the query. The 'filter_expr' is a pair:
|
||||||
(filter_string, value). E.g. ('name__contains', 'fred')
|
(filter_string, value). E.g. ('name__contains', 'fred')
|
||||||
|
|
||||||
If 'negate' is True, this is an exclude() filter. If 'trim' is True, we
|
If 'negate' is True, this is an exclude() filter. It's important to
|
||||||
automatically trim the final join group (used internally when
|
note that this method does not negate anything in the where-clause
|
||||||
constructing nested queries).
|
object when inserting the filter constraints. This is because negated
|
||||||
|
filters often require multiple calls to add_filter() and the negation
|
||||||
|
should only happen once. So the caller is responsible for this (the
|
||||||
|
caller will normally be add_q(), so that as an example).
|
||||||
|
|
||||||
|
If 'trim' is True, we automatically trim the final join group (used
|
||||||
|
internally when constructing nested queries).
|
||||||
|
|
||||||
If 'can_reuse' is a set, we are processing a component of a
|
If 'can_reuse' is a set, we are processing a component of a
|
||||||
multi-component filter (e.g. filter(Q1, Q2)). In this case, 'can_reuse'
|
multi-component filter (e.g. filter(Q1, Q2)). In this case, 'can_reuse'
|
||||||
@ -1001,7 +1007,6 @@ class Query(object):
|
|||||||
|
|
||||||
self.where.add((alias, col, field, lookup_type, value), connector)
|
self.where.add((alias, col, field, lookup_type, value), connector)
|
||||||
if negate:
|
if negate:
|
||||||
self.where.negate()
|
|
||||||
for alias in join_list:
|
for alias in join_list:
|
||||||
self.promote_alias(alias)
|
self.promote_alias(alias)
|
||||||
if final > 1 and lookup_type != 'isnull':
|
if final > 1 and lookup_type != 'isnull':
|
||||||
@ -1039,12 +1044,12 @@ class Query(object):
|
|||||||
self.where.start_subtree(connector)
|
self.where.start_subtree(connector)
|
||||||
self.add_q(child, used_aliases)
|
self.add_q(child, used_aliases)
|
||||||
self.where.end_subtree()
|
self.where.end_subtree()
|
||||||
if q_object.negated:
|
|
||||||
self.where.children[-1].negate()
|
|
||||||
else:
|
else:
|
||||||
self.add_filter(child, connector, q_object.negated,
|
self.add_filter(child, connector, q_object.negated,
|
||||||
can_reuse=used_aliases)
|
can_reuse=used_aliases)
|
||||||
connector = q_object.connector
|
connector = q_object.connector
|
||||||
|
if q_object.negated:
|
||||||
|
self.where.negate()
|
||||||
if subtree:
|
if subtree:
|
||||||
self.where.end_subtree()
|
self.where.end_subtree()
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ class UpdateQuery(Query):
|
|||||||
|
|
||||||
def _setup_query(self):
|
def _setup_query(self):
|
||||||
"""
|
"""
|
||||||
Runs on initialisation and after cloning. Any attributes that would
|
Runs on initialization and after cloning. Any attributes that would
|
||||||
normally be set in __init__ should go in here, instead, so that they
|
normally be set in __init__ should go in here, instead, so that they
|
||||||
are also set up after a clone() call.
|
are also set up after a clone() call.
|
||||||
"""
|
"""
|
||||||
@ -159,20 +159,37 @@ class UpdateQuery(Query):
|
|||||||
# from other tables.
|
# from other tables.
|
||||||
query = self.clone(klass=Query)
|
query = self.clone(klass=Query)
|
||||||
query.bump_prefix()
|
query.bump_prefix()
|
||||||
query.select = []
|
|
||||||
query.extra_select = {}
|
query.extra_select = {}
|
||||||
|
first_table = query.tables[0]
|
||||||
|
if query.alias_refcount[first_table] == 1:
|
||||||
|
# We can remove one table from the inner query.
|
||||||
|
query.unref_alias(first_table)
|
||||||
|
for i in xrange(1, len(query.tables)):
|
||||||
|
table = query.tables[i]
|
||||||
|
if query.alias_refcount[table]:
|
||||||
|
break
|
||||||
|
join_info = query.alias_map[table]
|
||||||
|
query.select = [(join_info[RHS_ALIAS], join_info[RHS_JOIN_COL])]
|
||||||
|
must_pre_select = False
|
||||||
|
else:
|
||||||
|
query.select = []
|
||||||
query.add_fields([query.model._meta.pk.name])
|
query.add_fields([query.model._meta.pk.name])
|
||||||
|
must_pre_select = not self.connection.features.update_can_self_select
|
||||||
|
|
||||||
# Now we adjust the current query: reset the where clause and get rid
|
# Now we adjust the current query: reset the where clause and get rid
|
||||||
# of all the tables we don't need (since they're in the sub-select).
|
# of all the tables we don't need (since they're in the sub-select).
|
||||||
self.where = self.where_class()
|
self.where = self.where_class()
|
||||||
if self.related_updates:
|
if self.related_updates or must_pre_select:
|
||||||
|
# Either we're using the idents in multiple update queries (so
|
||||||
|
# don't want them to change), or the db backend doesn't support
|
||||||
|
# selecting from the updating table (e.g. MySQL).
|
||||||
idents = []
|
idents = []
|
||||||
for rows in query.execute_sql(MULTI):
|
for rows in query.execute_sql(MULTI):
|
||||||
idents.extend([r[0] for r in rows])
|
idents.extend([r[0] for r in rows])
|
||||||
self.add_filter(('pk__in', idents))
|
self.add_filter(('pk__in', idents))
|
||||||
self.related_ids = idents
|
self.related_ids = idents
|
||||||
else:
|
else:
|
||||||
|
# The fast path. Filters and updates in one query.
|
||||||
self.add_filter(('pk__in', query))
|
self.add_filter(('pk__in', query))
|
||||||
for alias in self.tables[1:]:
|
for alias in self.tables[1:]:
|
||||||
self.alias_refcount[alias] = 0
|
self.alias_refcount[alias] = 0
|
||||||
@ -349,6 +366,7 @@ class DateQuery(Query):
|
|||||||
self.connection.ops.date_trunc_sql)
|
self.connection.ops.date_trunc_sql)
|
||||||
self.select = [select]
|
self.select = [select]
|
||||||
self.select_fields = [None]
|
self.select_fields = [None]
|
||||||
|
self.select_related = False # See #7097.
|
||||||
self.distinct = True
|
self.distinct = True
|
||||||
self.order_by = order == 'ASC' and [1] or [-1]
|
self.order_by = order == 'ASC' and [1] or [-1]
|
||||||
|
|
||||||
|
@ -527,7 +527,7 @@ applied to a query, not even the default ordering, call ``order_by()`` with no
|
|||||||
parameters.
|
parameters.
|
||||||
|
|
||||||
**New in Django development version:** The syntax for ordering across related
|
**New in Django development version:** The syntax for ordering across related
|
||||||
models has changed. See the `Django 0.96 documentation`_ for the old behaviour.
|
models has changed. See the `Django 0.96 documentation`_ for the old behavior.
|
||||||
|
|
||||||
.. _Django 0.96 documentation: http://www.djangoproject.com/documentation/0.96/model-api/#floatfield
|
.. _Django 0.96 documentation: http://www.djangoproject.com/documentation/0.96/model-api/#floatfield
|
||||||
|
|
||||||
@ -540,9 +540,9 @@ backend normally orders them.
|
|||||||
|
|
||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
|
||||||
If you want to reverse the order in which a queryset's elements are returned,
|
Use the ``reverse()`` method to reverse the order in which a queryset's
|
||||||
you can use the ``reverse()`` method. Calling ``reverse()`` a second time
|
elements are returned. Calling ``reverse()`` a second time restores the
|
||||||
restores the ordering back to the normal direction.
|
ordering back to the normal direction.
|
||||||
|
|
||||||
To retrieve the ''last'' five items in a queryset, you could do this::
|
To retrieve the ''last'' five items in a queryset, you could do this::
|
||||||
|
|
||||||
@ -552,7 +552,7 @@ Note that this is not quite the same as slicing from the end of a sequence in
|
|||||||
Python. The above example will return the last item first, then the
|
Python. The above example will return the last item first, then the
|
||||||
penultimate item and so on. If we had a Python sequence and looked at
|
penultimate item and so on. If we had a Python sequence and looked at
|
||||||
``seq[:-5]``, we would see the fifth-last item first. Django doesn't support
|
``seq[:-5]``, we would see the fifth-last item first. Django doesn't support
|
||||||
that mode of access (slicing from the end), since it is not possible to do it
|
that mode of access (slicing from the end), because it's not possible to do it
|
||||||
efficiently in SQL.
|
efficiently in SQL.
|
||||||
|
|
||||||
``distinct()``
|
``distinct()``
|
||||||
@ -1660,7 +1660,7 @@ entry. The entries select by the second filter may or may not be the same as
|
|||||||
the entries in the first filter. We are filtering the ``Blog`` items with each
|
the entries in the first filter. We are filtering the ``Blog`` items with each
|
||||||
filter statement, not the ``Entry`` items.
|
filter statement, not the ``Entry`` items.
|
||||||
|
|
||||||
All of this behaviour also applies to ``exclude()``: all the conditions in a
|
All of this behavior also applies to ``exclude()``: all the conditions in a
|
||||||
single ``exclude()`` statement apply to a single instance (if those conditions
|
single ``exclude()`` statement apply to a single instance (if those conditions
|
||||||
are talking about the same multi-valued relation). Conditions in subsequent
|
are talking about the same multi-valued relation). Conditions in subsequent
|
||||||
``filter()`` or ``exclude()`` calls that refer to the same relation may end up
|
``filter()`` or ``exclude()`` calls that refer to the same relation may end up
|
||||||
@ -2101,24 +2101,24 @@ Updating multiple objects at once
|
|||||||
**New in Django development version**
|
**New in Django development version**
|
||||||
|
|
||||||
Sometimes you want to set a field to a particular value for all the objects in
|
Sometimes you want to set a field to a particular value for all the objects in
|
||||||
a queryset. You can do this with the ``update()`` method. For example::
|
a ``QuerySet``. You can do this with the ``update()`` method. For example::
|
||||||
|
|
||||||
# Update all the headlines to the same value.
|
# Update all the headlines with pub_date in 2007.
|
||||||
Entry.objects.all().update(headline='Everything is the same')
|
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
|
||||||
|
|
||||||
You can only set non-relation fields and ``ForeignKey`` fields using this
|
You can only set non-relation fields and ``ForeignKey`` fields using this
|
||||||
method and the value you set the field to must be a normal Python value (you
|
method, and the value you set the field to must be a hard-coded Python value
|
||||||
can't set a field to be equal to some other field at the moment).
|
(i.e., you can't set a field to be equal to some other field at the moment).
|
||||||
|
|
||||||
To update ``ForeignKey`` fields, set the new value to be the new model
|
To update ``ForeignKey`` fields, set the new value to be the new model
|
||||||
instance you want to point to. Example::
|
instance you want to point to. Example::
|
||||||
|
|
||||||
b = Blog.objects.get(pk=1)
|
b = Blog.objects.get(pk=1)
|
||||||
# Make all entries belong to this blog.
|
# Change every Entry so that it belongs to this Blog.
|
||||||
Entry.objects.all().update(blog=b)
|
Entry.objects.all().update(blog=b)
|
||||||
|
|
||||||
The ``update()`` method is applied instantly and doesn't return anything
|
The ``update()`` method is applied instantly and doesn't return anything
|
||||||
(similar to ``delete()``). The only restriction on the queryset that is
|
(similar to ``delete()``). The only restriction on the ``QuerySet`` that is
|
||||||
updated is that it can only access one database table, the model's main
|
updated is that it can only access one database table, the model's main
|
||||||
table. So don't try to filter based on related fields or anything like that;
|
table. So don't try to filter based on related fields or anything like that;
|
||||||
it won't work.
|
it won't work.
|
||||||
|
@ -246,7 +246,7 @@ FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: headli
|
|||||||
>>> Reporter.objects.filter(article__reporter__exact=r).distinct()
|
>>> Reporter.objects.filter(article__reporter__exact=r).distinct()
|
||||||
[<Reporter: John Smith>]
|
[<Reporter: John Smith>]
|
||||||
|
|
||||||
# Check that implied __exact also works
|
# Check that implied __exact also works.
|
||||||
>>> Reporter.objects.filter(article__reporter=r).distinct()
|
>>> Reporter.objects.filter(article__reporter=r).distinct()
|
||||||
[<Reporter: John Smith>]
|
[<Reporter: John Smith>]
|
||||||
|
|
||||||
@ -266,11 +266,24 @@ True
|
|||||||
>>> Reporter.objects.order_by('first_name')
|
>>> Reporter.objects.order_by('first_name')
|
||||||
[<Reporter: John Smith>]
|
[<Reporter: John Smith>]
|
||||||
|
|
||||||
# Deletes using a join in the query
|
# You can delete using a JOIN in the query.
|
||||||
>>> Reporter.objects.filter(article__headline__startswith='This').delete()
|
>>> Reporter.objects.filter(article__headline__startswith='This').delete()
|
||||||
>>> Reporter.objects.all()
|
>>> Reporter.objects.all()
|
||||||
[]
|
[]
|
||||||
>>> Article.objects.all()
|
>>> Article.objects.all()
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
# Check that Article.objects.select_related().dates() works properly when
|
||||||
|
# there are multiple Articles with the same date but different foreign-key
|
||||||
|
# objects (Reporters).
|
||||||
|
>>> r1 = Reporter.objects.create(first_name='Mike', last_name='Royko', email='royko@suntimes.com')
|
||||||
|
>>> r2 = Reporter.objects.create(first_name='John', last_name='Kass', email='jkass@tribune.com')
|
||||||
|
>>> a1 = Article.objects.create(headline='First', pub_date=datetime(1980, 4, 23), reporter=r1)
|
||||||
|
>>> a2 = Article.objects.create(headline='Second', pub_date=datetime(1980, 4, 23), reporter=r2)
|
||||||
|
>>> Article.objects.select_related().dates('pub_date', 'day')
|
||||||
|
[datetime.datetime(1980, 4, 23, 0, 0)]
|
||||||
|
>>> Article.objects.select_related().dates('pub_date', 'month')
|
||||||
|
[datetime.datetime(1980, 4, 1, 0, 0)]
|
||||||
|
>>> Article.objects.select_related().dates('pub_date', 'year')
|
||||||
|
[datetime.datetime(1980, 1, 1, 0, 0)]
|
||||||
"""}
|
"""}
|
||||||
|
@ -117,6 +117,24 @@ class LoopZ(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['z']
|
ordering = ['z']
|
||||||
|
|
||||||
|
# A model and custom default manager combination.
|
||||||
|
class CustomManager(models.Manager):
|
||||||
|
def get_query_set(self):
|
||||||
|
return super(CustomManager, self).get_query_set().filter(public=True,
|
||||||
|
tag__name='t1')
|
||||||
|
|
||||||
|
class ManagedModel(models.Model):
|
||||||
|
data = models.CharField(max_length=10)
|
||||||
|
tag = models.ForeignKey(Tag)
|
||||||
|
public = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
objects = CustomManager()
|
||||||
|
normal_manager = models.Manager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
|
||||||
__test__ = {'API_TESTS':"""
|
__test__ = {'API_TESTS':"""
|
||||||
>>> t1 = Tag(name='t1')
|
>>> t1 = Tag(name='t1')
|
||||||
>>> t1.save()
|
>>> t1.save()
|
||||||
@ -654,5 +672,34 @@ Bug #7045 -- extra tables used to crash SQL construction on the second use.
|
|||||||
>>> s = qs.query.as_sql()
|
>>> s = qs.query.as_sql()
|
||||||
>>> s = qs.query.as_sql() # test passes if this doesn't raise an exception.
|
>>> s = qs.query.as_sql() # test passes if this doesn't raise an exception.
|
||||||
|
|
||||||
|
Bug #7098 -- Make sure semi-deprecated ordering by related models syntax still
|
||||||
|
works.
|
||||||
|
>>> Item.objects.values('note__note').order_by('queries_note.note', 'id')
|
||||||
|
[{'note__note': u'n2'}, {'note__note': u'n3'}, {'note__note': u'n3'}, {'note__note': u'n3'}]
|
||||||
|
|
||||||
|
Bug #7096 -- Make sure exclude() with multiple conditions continues to work.
|
||||||
|
>>> Tag.objects.filter(parent=t1, name='t3').order_by('name')
|
||||||
|
[<Tag: t3>]
|
||||||
|
>>> Tag.objects.exclude(parent=t1, name='t3').order_by('name')
|
||||||
|
[<Tag: t1>, <Tag: t2>, <Tag: t4>, <Tag: t5>]
|
||||||
|
>>> Item.objects.exclude(tags__name='t1', name='one').order_by('name').distinct()
|
||||||
|
[<Item: four>, <Item: three>, <Item: two>]
|
||||||
|
>>> Item.objects.filter(name__in=['three', 'four']).exclude(tags__name='t1').order_by('name')
|
||||||
|
[<Item: four>, <Item: three>]
|
||||||
|
|
||||||
|
More twisted cases, involving nested negations.
|
||||||
|
>>> Item.objects.exclude(~Q(tags__name='t1', name='one'))
|
||||||
|
[<Item: one>]
|
||||||
|
>>> Item.objects.filter(~Q(tags__name='t1', name='one'), name='two')
|
||||||
|
[<Item: two>]
|
||||||
|
>>> Item.objects.exclude(~Q(tags__name='t1', name='one'), name='two')
|
||||||
|
[<Item: four>, <Item: one>, <Item: three>]
|
||||||
|
|
||||||
|
Bug #7095
|
||||||
|
Updates that are filtered on the model being updated are somewhat tricky to get
|
||||||
|
in MySQL. This exercises that case.
|
||||||
|
>>> mm = ManagedModel.objects.create(data='mm1', tag=t1, public=True)
|
||||||
|
>>> ManagedModel.objects.update(data='mm')
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user