mirror of
https://github.com/django/django.git
synced 2024-12-26 02:56:25 +00:00
baa960209f
Any extra(select=...) columns can be ignored in the SQL for dates, since we are only interested in extracting distinct date values. We were previously including them by accident and it was generating incorrect SQL. git-svn-id: http://code.djangoproject.com/svn/django/trunk@9091 bcc190cf-cafb-0310-a4f2-bffc1f526a37
119 lines
4.6 KiB
Python
119 lines
4.6 KiB
Python
import copy
|
|
import datetime
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.db import models
|
|
from django.db.models.query import Q
|
|
from django.utils.datastructures import SortedDict
|
|
|
|
|
|
class RevisionableModel(models.Model):
|
|
base = models.ForeignKey('self', null=True)
|
|
title = models.CharField(blank=True, max_length=255)
|
|
when = models.DateTimeField(default=datetime.datetime.now)
|
|
|
|
def __unicode__(self):
|
|
return u"%s (%s, %s)" % (self.title, self.id, self.base.id)
|
|
|
|
def save(self, force_insert=False, force_update=False):
|
|
super(RevisionableModel, self).save(force_insert, force_update)
|
|
if not self.base:
|
|
self.base = self
|
|
super(RevisionableModel, self).save()
|
|
|
|
def new_revision(self):
|
|
new_revision = copy.copy(self)
|
|
new_revision.pk = None
|
|
return new_revision
|
|
|
|
class Order(models.Model):
|
|
created_by = models.ForeignKey(User)
|
|
text = models.TextField()
|
|
|
|
__test__ = {"API_TESTS": """
|
|
# Regression tests for #7314 and #7372
|
|
|
|
>>> rm = RevisionableModel.objects.create(title='First Revision', when=datetime.datetime(2008, 9, 28, 10, 30, 0))
|
|
>>> rm.pk, rm.base.pk
|
|
(1, 1)
|
|
|
|
>>> rm2 = rm.new_revision()
|
|
>>> rm2.title = "Second Revision"
|
|
>>> rm.when = datetime.datetime(2008, 9, 28, 14, 25, 0)
|
|
>>> rm2.save()
|
|
>>> print u"%s of %s" % (rm2.title, rm2.base.title)
|
|
Second Revision of First Revision
|
|
|
|
>>> rm2.pk, rm2.base.pk
|
|
(2, 1)
|
|
|
|
Queryset to match most recent revision:
|
|
>>> qs = RevisionableModel.objects.extra(where=["%(table)s.id IN (SELECT MAX(rev.id) FROM %(table)s rev GROUP BY rev.base_id)" % {'table': RevisionableModel._meta.db_table,}],)
|
|
>>> qs
|
|
[<RevisionableModel: Second Revision (2, 1)>]
|
|
|
|
Queryset to search for string in title:
|
|
>>> qs2 = RevisionableModel.objects.filter(title__contains="Revision")
|
|
>>> qs2
|
|
[<RevisionableModel: First Revision (1, 1)>, <RevisionableModel: Second Revision (2, 1)>]
|
|
|
|
Following queryset should return the most recent revision:
|
|
>>> qs & qs2
|
|
[<RevisionableModel: Second Revision (2, 1)>]
|
|
|
|
>>> u = User.objects.create_user(username="fred", password="secret", email="fred@example.com")
|
|
|
|
# General regression tests: extra select parameters should stay tied to their
|
|
# corresponding select portions. Applies when portions are updated or otherwise
|
|
# moved around.
|
|
>>> qs = User.objects.extra(select=SortedDict((("alpha", "%s"), ("beta", "2"), ("gamma", "%s"))), select_params=(1, 3))
|
|
>>> qs = qs.extra(select={"beta": 4})
|
|
>>> qs = qs.extra(select={"alpha": "%s"}, select_params=[5])
|
|
>>> result = {'alpha': 5, 'beta': 4, 'gamma': 3}
|
|
>>> list(qs.filter(id=u.id).values('alpha', 'beta', 'gamma')) == [result]
|
|
True
|
|
|
|
# Regression test for #7957: Combining extra() calls should leave the
|
|
# corresponding parameters associated with the right extra() bit. I.e. internal
|
|
# dictionary must remain sorted.
|
|
>>> User.objects.extra(select={"alpha": "%s"}, select_params=(1,)).extra(select={"beta": "%s"}, select_params=(2,))[0].alpha
|
|
1
|
|
>>> User.objects.extra(select={"beta": "%s"}, select_params=(1,)).extra(select={"alpha": "%s"}, select_params=(2,))[0].alpha
|
|
2
|
|
|
|
# Regression test for #7961: When not using a portion of an extra(...) in a
|
|
# query, remove any corresponding parameters from the query as well.
|
|
>>> list(User.objects.extra(select={"alpha": "%s"}, select_params=(-6,)).filter(id=u.id).values_list('id', flat=True)) == [u.id]
|
|
True
|
|
|
|
# Regression test for #8063: limiting a query shouldn't discard any extra()
|
|
# bits.
|
|
>>> qs = User.objects.all().extra(where=['id=%s'], params=[u.id])
|
|
>>> qs
|
|
[<User: fred>]
|
|
>>> qs[:1]
|
|
[<User: fred>]
|
|
|
|
# Regression test for #8039: Ordering sometimes removed relevant tables from
|
|
# extra(). This test is the critical case: ordering uses a table, but then
|
|
# removes the reference because of an optimisation. The table should still be
|
|
# present because of the extra() call.
|
|
>>> Order.objects.extra(where=["username=%s"], params=["fred"], tables=["auth_user"]).order_by('created_by')
|
|
[]
|
|
|
|
# Regression test for #8819: Fields in the extra(select=...) list should be
|
|
# available to extra(order_by=...).
|
|
>>> User.objects.filter(pk=u.id).extra(select={'extra_field': 1}).distinct()
|
|
[<User: fred>]
|
|
>>> User.objects.filter(pk=u.id).extra(select={'extra_field': 1}, order_by=['extra_field'])
|
|
[<User: fred>]
|
|
>>> User.objects.filter(pk=u.id).extra(select={'extra_field': 1}, order_by=['extra_field']).distinct()
|
|
[<User: fred>]
|
|
|
|
# When calling the dates() method on a queryset with extra selection columns,
|
|
# we can (and should) ignore those columns. They don't change the result and
|
|
# cause incorrect SQL to be produced otherwise.
|
|
>>> RevisionableModel.objects.extra(select={"the_answer": 'id'}).dates('when', 'month')
|
|
[datetime.datetime(2008, 9, 1, 0, 0)]
|
|
"""}
|