mirror of
https://github.com/django/django.git
synced 2025-07-04 01:39:20 +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()
|
||||
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.
|
||||
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.
|
||||
def construct_search(field_name):
|
||||
|
@ -51,6 +51,7 @@ class BaseDatabaseFeatures(object):
|
||||
uses_case_insensitive_names = False
|
||||
uses_custom_query_class = False
|
||||
empty_fetchmany_value = []
|
||||
update_can_self_select = True
|
||||
|
||||
class BaseDatabaseOperations(object):
|
||||
"""
|
||||
|
@ -63,6 +63,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
autoindexes_primary_keys = False
|
||||
inline_fk_references = False
|
||||
empty_fetchmany_value = ()
|
||||
update_can_self_select = False
|
||||
|
||||
class DatabaseOperations(BaseDatabaseOperations):
|
||||
def date_extract_sql(self, lookup_type, field_name):
|
||||
|
@ -67,6 +67,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
autoindexes_primary_keys = False
|
||||
inline_fk_references = False
|
||||
empty_fetchmany_value = ()
|
||||
update_can_self_select = False
|
||||
|
||||
class DatabaseOperations(BaseDatabaseOperations):
|
||||
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.models import signals
|
||||
from django.db.models.query_utils import QueryWrapper
|
||||
from django.dispatch import dispatcher
|
||||
from django.conf import settings
|
||||
from django.core import validators
|
||||
@ -226,6 +227,9 @@ class Field(object):
|
||||
|
||||
def get_db_prep_lookup(self, lookup_type, value):
|
||||
"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'):
|
||||
return [value]
|
||||
elif lookup_type in ('range', 'in'):
|
||||
|
@ -284,6 +284,7 @@ class QuerySet(object):
|
||||
query = self.query.clone(sql.UpdateQuery)
|
||||
query.add_update_values(kwargs)
|
||||
query.execute_sql(None)
|
||||
transaction.commit_unless_managed()
|
||||
self._result_cache = None
|
||||
update.alters_data = True
|
||||
|
||||
@ -496,9 +497,6 @@ class ValuesQuerySet(QuerySet):
|
||||
# QuerySet.clone() will also set up the _fields attribute with the
|
||||
# names of the model fields to select.
|
||||
|
||||
def __iter__(self):
|
||||
return self.iterator()
|
||||
|
||||
def iterator(self):
|
||||
self.query.trim_extra_select(self.extra_names)
|
||||
names = self.query.extra_select.keys() + self.field_names
|
||||
|
@ -28,7 +28,7 @@ NULLABLE = 6
|
||||
MULTI = 'multi'
|
||||
SINGLE = 'single'
|
||||
|
||||
ORDER_PATTERN = re.compile(r'\?|[-+]?\w+$')
|
||||
ORDER_PATTERN = re.compile(r'\?|[-+]?[.\w]+$')
|
||||
ORDER_DIR = {
|
||||
'ASC': ('ASC', 'DESC'),
|
||||
'DESC': ('DESC', 'ASC')}
|
||||
|
@ -895,9 +895,15 @@ class Query(object):
|
||||
Add a single filter to the query. The 'filter_expr' is a pair:
|
||||
(filter_string, value). E.g. ('name__contains', 'fred')
|
||||
|
||||
If 'negate' is True, this is an exclude() filter. If 'trim' is True, we
|
||||
automatically trim the final join group (used internally when
|
||||
constructing nested queries).
|
||||
If 'negate' is True, this is an exclude() filter. It's important to
|
||||
note that this method does not negate anything in the where-clause
|
||||
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
|
||||
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)
|
||||
if negate:
|
||||
self.where.negate()
|
||||
for alias in join_list:
|
||||
self.promote_alias(alias)
|
||||
if final > 1 and lookup_type != 'isnull':
|
||||
@ -1039,12 +1044,12 @@ class Query(object):
|
||||
self.where.start_subtree(connector)
|
||||
self.add_q(child, used_aliases)
|
||||
self.where.end_subtree()
|
||||
if q_object.negated:
|
||||
self.where.children[-1].negate()
|
||||
else:
|
||||
self.add_filter(child, connector, q_object.negated,
|
||||
can_reuse=used_aliases)
|
||||
connector = q_object.connector
|
||||
if q_object.negated:
|
||||
self.where.negate()
|
||||
if subtree:
|
||||
self.where.end_subtree()
|
||||
|
||||
|
@ -95,7 +95,7 @@ class UpdateQuery(Query):
|
||||
|
||||
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
|
||||
are also set up after a clone() call.
|
||||
"""
|
||||
@ -159,20 +159,37 @@ class UpdateQuery(Query):
|
||||
# from other tables.
|
||||
query = self.clone(klass=Query)
|
||||
query.bump_prefix()
|
||||
query.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])
|
||||
must_pre_select = not self.connection.features.update_can_self_select
|
||||
|
||||
# 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).
|
||||
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 = []
|
||||
for rows in query.execute_sql(MULTI):
|
||||
idents.extend([r[0] for r in rows])
|
||||
self.add_filter(('pk__in', idents))
|
||||
self.related_ids = idents
|
||||
else:
|
||||
# The fast path. Filters and updates in one query.
|
||||
self.add_filter(('pk__in', query))
|
||||
for alias in self.tables[1:]:
|
||||
self.alias_refcount[alias] = 0
|
||||
@ -349,6 +366,7 @@ class DateQuery(Query):
|
||||
self.connection.ops.date_trunc_sql)
|
||||
self.select = [select]
|
||||
self.select_fields = [None]
|
||||
self.select_related = False # See #7097.
|
||||
self.distinct = True
|
||||
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.
|
||||
|
||||
**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
|
||||
|
||||
@ -540,9 +540,9 @@ backend normally orders them.
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
If you want to reverse the order in which a queryset's elements are returned,
|
||||
you can use the ``reverse()`` method. Calling ``reverse()`` a second time
|
||||
restores the ordering back to the normal direction.
|
||||
Use the ``reverse()`` method to reverse the order in which a queryset's
|
||||
elements are returned. Calling ``reverse()`` a second time restores the
|
||||
ordering back to the normal direction.
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
``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
|
||||
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
|
||||
are talking about the same multi-valued relation). Conditions in subsequent
|
||||
``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**
|
||||
|
||||
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.
|
||||
Entry.objects.all().update(headline='Everything is the same')
|
||||
# Update all the headlines with pub_date in 2007.
|
||||
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
|
||||
method and the value you set the field to must be a normal Python value (you
|
||||
can't set a field to be equal to some other field at the moment).
|
||||
method, and the value you set the field to must be a hard-coded Python value
|
||||
(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
|
||||
instance you want to point to. Example::
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
table. So don't try to filter based on related fields or anything like that;
|
||||
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: John Smith>]
|
||||
|
||||
# Check that implied __exact also works
|
||||
# Check that implied __exact also works.
|
||||
>>> Reporter.objects.filter(article__reporter=r).distinct()
|
||||
[<Reporter: John Smith>]
|
||||
|
||||
@ -266,11 +266,24 @@ True
|
||||
>>> Reporter.objects.order_by('first_name')
|
||||
[<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.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:
|
||||
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':"""
|
||||
>>> t1 = Tag(name='t1')
|
||||
>>> 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() # 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