~ubuntu-branches/debian/sid/python-django/sid

« back to all changes in this revision

Viewing changes to tests/modeltests/generic_relations/tests.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone
  • Date: 2013-11-07 15:33:49 UTC
  • mfrom: (1.3.12)
  • Revision ID: package-import@ubuntu.com-20131107153349-e31sc149l2szs3jb
Tags: 1.6-1
* New upstream version. Closes: #557474, #724637.
* python-django now also suggests the installation of ipython,
  bpython, python-django-doc, and libgdal1.
  Closes: #636511, #686333, #704203
* Set package maintainer to Debian Python Modules Team.
* Bump standards version to 3.9.5, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from __future__ import absolute_import, unicode_literals
2
 
 
3
 
from django import forms
4
 
from django.contrib.contenttypes.generic import generic_inlineformset_factory
5
 
from django.contrib.contenttypes.models import ContentType
6
 
from django.test import TestCase
7
 
 
8
 
from .models import (TaggedItem, ValuableTaggedItem, Comparison, Animal,
9
 
    Vegetable, Mineral, Gecko)
10
 
 
11
 
 
12
 
class GenericRelationsTests(TestCase):
13
 
    def test_generic_relations(self):
14
 
        # Create the world in 7 lines of code...
15
 
        lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo")
16
 
        platypus = Animal.objects.create(
17
 
            common_name="Platypus", latin_name="Ornithorhynchus anatinus"
18
 
        )
19
 
        eggplant = Vegetable.objects.create(name="Eggplant", is_yucky=True)
20
 
        bacon = Vegetable.objects.create(name="Bacon", is_yucky=False)
21
 
        quartz = Mineral.objects.create(name="Quartz", hardness=7)
22
 
 
23
 
        # Objects with declared GenericRelations can be tagged directly -- the
24
 
        # API mimics the many-to-many API.
25
 
        bacon.tags.create(tag="fatty")
26
 
        bacon.tags.create(tag="salty")
27
 
        lion.tags.create(tag="yellow")
28
 
        lion.tags.create(tag="hairy")
29
 
        platypus.tags.create(tag="fatty")
30
 
        self.assertQuerysetEqual(lion.tags.all(), [
31
 
            "<TaggedItem: hairy>",
32
 
            "<TaggedItem: yellow>"
33
 
        ])
34
 
        self.assertQuerysetEqual(bacon.tags.all(), [
35
 
            "<TaggedItem: fatty>",
36
 
            "<TaggedItem: salty>"
37
 
        ])
38
 
 
39
 
        # You can easily access the content object like a foreign key.
40
 
        t = TaggedItem.objects.get(tag="salty")
41
 
        self.assertEqual(t.content_object, bacon)
42
 
 
43
 
        # Recall that the Mineral class doesn't have an explicit GenericRelation
44
 
        # defined. That's OK, because you can create TaggedItems explicitly.
45
 
        tag1 = TaggedItem.objects.create(content_object=quartz, tag="shiny")
46
 
        tag2 = TaggedItem.objects.create(content_object=quartz, tag="clearish")
47
 
 
48
 
        # However, excluding GenericRelations means your lookups have to be a
49
 
        # bit more explicit.
50
 
        ctype = ContentType.objects.get_for_model(quartz)
51
 
        q = TaggedItem.objects.filter(
52
 
            content_type__pk=ctype.id, object_id=quartz.id
53
 
        )
54
 
        self.assertQuerysetEqual(q, [
55
 
            "<TaggedItem: clearish>",
56
 
            "<TaggedItem: shiny>"
57
 
        ])
58
 
 
59
 
        # You can set a generic foreign key in the way you'd expect.
60
 
        tag1.content_object = platypus
61
 
        tag1.save()
62
 
        self.assertQuerysetEqual(platypus.tags.all(), [
63
 
            "<TaggedItem: fatty>",
64
 
            "<TaggedItem: shiny>"
65
 
        ])
66
 
        q = TaggedItem.objects.filter(
67
 
            content_type__pk=ctype.id, object_id=quartz.id
68
 
        )
69
 
        self.assertQuerysetEqual(q, ["<TaggedItem: clearish>"])
70
 
 
71
 
        # Queries across generic relations respect the content types. Even
72
 
        # though there are two TaggedItems with a tag of "fatty", this query
73
 
        # only pulls out the one with the content type related to Animals.
74
 
        self.assertQuerysetEqual(Animal.objects.order_by('common_name'), [
75
 
            "<Animal: Lion>",
76
 
            "<Animal: Platypus>"
77
 
        ])
78
 
        self.assertQuerysetEqual(Animal.objects.filter(tags__tag='fatty'), [
79
 
            "<Animal: Platypus>"
80
 
        ])
81
 
        self.assertQuerysetEqual(Animal.objects.exclude(tags__tag='fatty'), [
82
 
            "<Animal: Lion>"
83
 
        ])
84
 
 
85
 
        # If you delete an object with an explicit Generic relation, the related
86
 
        # objects are deleted when the source object is deleted.
87
 
        # Original list of tags:
88
 
        comp_func = lambda obj: (
89
 
            obj.tag, obj.content_type.model_class(), obj.object_id
90
 
        )
91
 
 
92
 
        self.assertQuerysetEqual(TaggedItem.objects.all(), [
93
 
                ('clearish', Mineral, quartz.pk),
94
 
                ('fatty', Animal, platypus.pk),
95
 
                ('fatty', Vegetable, bacon.pk),
96
 
                ('hairy', Animal, lion.pk),
97
 
                ('salty', Vegetable, bacon.pk),
98
 
                ('shiny', Animal, platypus.pk),
99
 
                ('yellow', Animal, lion.pk)
100
 
            ],
101
 
            comp_func
102
 
        )
103
 
        lion.delete()
104
 
        self.assertQuerysetEqual(TaggedItem.objects.all(), [
105
 
                ('clearish', Mineral, quartz.pk),
106
 
                ('fatty', Animal, platypus.pk),
107
 
                ('fatty', Vegetable, bacon.pk),
108
 
                ('salty', Vegetable, bacon.pk),
109
 
                ('shiny', Animal, platypus.pk)
110
 
            ],
111
 
            comp_func
112
 
        )
113
 
 
114
 
        # If Generic Relation is not explicitly defined, any related objects
115
 
        # remain after deletion of the source object.
116
 
        quartz_pk = quartz.pk
117
 
        quartz.delete()
118
 
        self.assertQuerysetEqual(TaggedItem.objects.all(), [
119
 
                ('clearish', Mineral, quartz_pk),
120
 
                ('fatty', Animal, platypus.pk),
121
 
                ('fatty', Vegetable, bacon.pk),
122
 
                ('salty', Vegetable, bacon.pk),
123
 
                ('shiny', Animal, platypus.pk)
124
 
            ],
125
 
            comp_func
126
 
        )
127
 
        # If you delete a tag, the objects using the tag are unaffected
128
 
        # (other than losing a tag)
129
 
        tag = TaggedItem.objects.order_by("id")[0]
130
 
        tag.delete()
131
 
        self.assertQuerysetEqual(bacon.tags.all(), ["<TaggedItem: salty>"])
132
 
        self.assertQuerysetEqual(TaggedItem.objects.all(), [
133
 
                ('clearish', Mineral, quartz_pk),
134
 
                ('fatty', Animal, platypus.pk),
135
 
                ('salty', Vegetable, bacon.pk),
136
 
                ('shiny', Animal, platypus.pk)
137
 
            ],
138
 
            comp_func
139
 
        )
140
 
        TaggedItem.objects.filter(tag='fatty').delete()
141
 
        ctype = ContentType.objects.get_for_model(lion)
142
 
        self.assertQuerysetEqual(Animal.objects.filter(tags__content_type=ctype), [
143
 
            "<Animal: Platypus>"
144
 
        ])
145
 
 
146
 
 
147
 
    def test_multiple_gfk(self):
148
 
        # Simple tests for multiple GenericForeignKeys
149
 
        # only uses one model, since the above tests should be sufficient.
150
 
        tiger = Animal.objects.create(common_name="tiger")
151
 
        cheetah = Animal.objects.create(common_name="cheetah")
152
 
        bear = Animal.objects.create(common_name="bear")
153
 
 
154
 
        # Create directly
155
 
        Comparison.objects.create(
156
 
            first_obj=cheetah, other_obj=tiger, comparative="faster"
157
 
        )
158
 
        Comparison.objects.create(
159
 
            first_obj=tiger, other_obj=cheetah, comparative="cooler"
160
 
        )
161
 
 
162
 
        # Create using GenericRelation
163
 
        tiger.comparisons.create(other_obj=bear, comparative="cooler")
164
 
        tiger.comparisons.create(other_obj=cheetah, comparative="stronger")
165
 
        self.assertQuerysetEqual(cheetah.comparisons.all(), [
166
 
            "<Comparison: cheetah is faster than tiger>"
167
 
        ])
168
 
 
169
 
        # Filtering works
170
 
        self.assertQuerysetEqual(tiger.comparisons.filter(comparative="cooler"), [
171
 
            "<Comparison: tiger is cooler than cheetah>",
172
 
            "<Comparison: tiger is cooler than bear>"
173
 
        ])
174
 
 
175
 
        # Filtering and deleting works
176
 
        subjective = ["cooler"]
177
 
        tiger.comparisons.filter(comparative__in=subjective).delete()
178
 
        self.assertQuerysetEqual(Comparison.objects.all(), [
179
 
            "<Comparison: cheetah is faster than tiger>",
180
 
            "<Comparison: tiger is stronger than cheetah>"
181
 
        ])
182
 
 
183
 
        # If we delete cheetah, Comparisons with cheetah as 'first_obj' will be
184
 
        # deleted since Animal has an explicit GenericRelation to Comparison
185
 
        # through first_obj. Comparisons with cheetah as 'other_obj' will not
186
 
        # be deleted.
187
 
        cheetah.delete()
188
 
        self.assertQuerysetEqual(Comparison.objects.all(), [
189
 
            "<Comparison: tiger is stronger than None>"
190
 
        ])
191
 
 
192
 
    def test_gfk_subclasses(self):
193
 
        # GenericForeignKey should work with subclasses (see #8309)
194
 
        quartz = Mineral.objects.create(name="Quartz", hardness=7)
195
 
        valuedtag = ValuableTaggedItem.objects.create(
196
 
            content_object=quartz, tag="shiny", value=10
197
 
        )
198
 
        self.assertEqual(valuedtag.content_object, quartz)
199
 
 
200
 
    def test_generic_inline_formsets(self):
201
 
        GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1)
202
 
        formset = GenericFormSet()
203
 
        self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50" /></p>
204
 
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>""")
205
 
 
206
 
        formset = GenericFormSet(instance=Animal())
207
 
        self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" maxlength="50" /></p>
208
 
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p>""")
209
 
 
210
 
        platypus = Animal.objects.create(
211
 
            common_name="Platypus", latin_name="Ornithorhynchus anatinus"
212
 
        )
213
 
        platypus.tags.create(tag="shiny")
214
 
        GenericFormSet = generic_inlineformset_factory(TaggedItem, extra=1)
215
 
        formset = GenericFormSet(instance=platypus)
216
 
        tagged_item_id = TaggedItem.objects.get(
217
 
            tag='shiny', object_id=platypus.id
218
 
        ).id
219
 
        self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-0-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-0-tag" value="shiny" maxlength="50" /></p>
220
 
<p><label for="id_generic_relations-taggeditem-content_type-object_id-0-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-0-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-0-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-0-id" value="%s" id="id_generic_relations-taggeditem-content_type-object_id-0-id" /></p><p><label for="id_generic_relations-taggeditem-content_type-object_id-1-tag">Tag:</label> <input id="id_generic_relations-taggeditem-content_type-object_id-1-tag" type="text" name="generic_relations-taggeditem-content_type-object_id-1-tag" maxlength="50" /></p>
221
 
<p><label for="id_generic_relations-taggeditem-content_type-object_id-1-DELETE">Delete:</label> <input type="checkbox" name="generic_relations-taggeditem-content_type-object_id-1-DELETE" id="id_generic_relations-taggeditem-content_type-object_id-1-DELETE" /><input type="hidden" name="generic_relations-taggeditem-content_type-object_id-1-id" id="id_generic_relations-taggeditem-content_type-object_id-1-id" /></p>""" % tagged_item_id)
222
 
 
223
 
        lion = Animal.objects.create(common_name="Lion", latin_name="Panthera leo")
224
 
        formset = GenericFormSet(instance=lion, prefix='x')
225
 
        self.assertHTMLEqual(''.join(form.as_p() for form in formset.forms), """<p><label for="id_x-0-tag">Tag:</label> <input id="id_x-0-tag" type="text" name="x-0-tag" maxlength="50" /></p>
226
 
<p><label for="id_x-0-DELETE">Delete:</label> <input type="checkbox" name="x-0-DELETE" id="id_x-0-DELETE" /><input type="hidden" name="x-0-id" id="id_x-0-id" /></p>""")
227
 
 
228
 
    def test_gfk_manager(self):
229
 
        # GenericForeignKey should not use the default manager (which may filter objects) #16048
230
 
        tailless = Gecko.objects.create(has_tail=False)
231
 
        tag = TaggedItem.objects.create(content_object=tailless, tag="lizard")
232
 
        self.assertEqual(tag.content_object, tailless)
233
 
 
234
 
class CustomWidget(forms.TextInput):
235
 
    pass
236
 
 
237
 
class TaggedItemForm(forms.ModelForm):
238
 
    class Meta:
239
 
        model = TaggedItem
240
 
        widgets = {'tag': CustomWidget}
241
 
 
242
 
class GenericInlineFormsetTest(TestCase):
243
 
    """
244
 
    Regression for #14572: Using base forms with widgets
245
 
    defined in Meta should not raise errors.
246
 
    """
247
 
 
248
 
    def test_generic_inlineformset_factory(self):
249
 
        Formset = generic_inlineformset_factory(TaggedItem, TaggedItemForm)
250
 
        form = Formset().forms[0]
251
 
        self.assertTrue(isinstance(form['tag'].field.widget, CustomWidget))