summaryrefslogtreecommitdiff
path: root/tests/regressiontests/extra_regress/models.py
blob: 680917b8ae5c11668642d1970fe7169a05d3e192 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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)]
"""}