Ticket #12760: tests.py

File tests.py, 6.4 KB (added by defaultwombat, 6 years ago)

Testfile with 2 Models

Line 
1from django.db import models
2from django.contrib.auth.models import User
3
4
5# #
6# THE SETUP
7# #
8
9class Human(models.Model):
10  """A Human MAY have a user assigned"""
11  name = models.CharField(blank=False,null=False,max_length=100) 
12  auth_user = models.ForeignKey(User,blank=True,null=True)
13  def __unicode__(self):
14      return self.name
15
16class Joke(models.Model):
17  """a Joke must have owner """
18  text = models.TextField(blank=False,null=False)
19  owner = models.ForeignKey(Human,blank=False,null=False)
20
21# #
22# THE TEST
23# #
24
25from django.test import TestCase
26from django.db.models.query_utils import CollectedObjects
27
28class SimpleTest(TestCase):
29   
30    def setUp(self):
31        user = User(username='Authtester',password="secret")
32        user.save()
33
34        human = Human(name='HumanTester',auth_user=user)
35        human.save()
36
37        joke = Joke(text='phunny Joke....',owner=human)
38        joke.save()
39       
40        self.user ,self.human,self.joke= user,human,joke
41
42    def test1(self):
43        """
44        The deletion of a User should disconnect it from a Human, but should not delete the Human, neither its Joke)
45        """
46        user, human, joke = self.user, self.human, self.joke
47        user.delete()
48
49        self.assertTrue(len(Human.objects.all()), u'there is no human left')
50        self.assertTrue(len(Joke.objects.all()), u'there is no Joke left')
51
52    def test2(self):
53        """
54        inspecting the objects getting collected by calling delete on a user
55        """
56        user, human, joke = self.user, self.human, self.joke
57
58        seen = CollectedObjects()
59        # calling the collection method used in delete
60        user._collect_sub_objects(seen)
61
62        collected_instances = []
63        for cls,instances in seen.items():
64            collected_instances.extend(instances.values())
65
66        self.assertFalse(joke in collected_instances,u'%s should not get collected because the human.user can be set to "NULL".'%joke)
67        # _collect_sub_objects keeps collection relations and their subrelations
68        # There should be no futher evaluation of sub-relations if a relation can be set to null
69       
70    def test3(self):
71        """
72        printing out what happens in the delete_objects funciton
73        """
74        user, human, joke = self.user, self.human, self.joke
75
76        seen = CollectedObjects()
77        user._collect_sub_objects(seen)
78        copy_of_delete_objects(seen)
79
80
81# ############################################################################## #       
82# # this is copy of db.models.query.py delete_objects (django version: 1.1.1.)
83# # spiced with some ugly prints to see what happens there
84# ############################################################################## #
85from django.db import connection, transaction
86from django.db.models import signals, sql
87
88def copy_of_delete_objects(seen_objs):
89    print
90    print "."*40
91    print "  the delte_object slow-mo"
92    print "."*40
93    """
94    Iterate through a list of seen classes, and remove any instances that are
95    referred to.
96    """
97    if not transaction.is_managed():
98        transaction.enter_transaction_management()
99        forced_managed = True
100    else:
101        forced_managed = False
102    try:
103        ordered_classes = seen_objs.keys()
104    except CyclicDependency:
105        # If there is a cyclic dependency, we cannot in general delete the
106        # objects.  However, if an appropriate transaction is set up, or if the
107        # database is lax enough, it will succeed. So for now, we go ahead and
108        # try anyway.
109        ordered_classes = seen_objs.unordered_keys()
110
111    obj_pairs = {}
112    print
113    try:
114        print "1. LOOP over ordered_classes"
115        for cls in ordered_classes:
116            print 'Class: ',cls
117            items = seen_objs[cls].items()
118            items.sort()
119            obj_pairs[cls] = items
120
121            # Pre-notify all instances to be deleted.
122            for pk_val, instance in items:
123                signals.pre_delete.send(sender=cls, instance=instance)
124
125            pk_list = [pk for pk,instance in items]
126            print cls.__name__,"Primarykeys used for delete_batch_related: ",tuple(pk_list)
127            del_query = sql.DeleteQuery(cls, connection)
128            del_query.delete_batch_related(pk_list)
129
130            update_query = sql.UpdateQuery(cls, connection)
131            print cls.__name__, 'UPDATE Queries used'
132            for field, model in cls._meta.get_fields_with_model():
133                if (field.rel and field.null and field.rel.to in seen_objs and
134                        filter(lambda f: f.column == field.rel.get_related_field().column,
135                        field.rel.to._meta.fields)):
136                    if model:
137                        sql.UpdateQuery(model, connection).clear_related(field,
138                                pk_list)
139                    else:
140                        update_query.clear_related(field, pk_list)
141
142            print update_query or 'NONE'
143        print 
144        print "2. LOOP over ordered_classes"
145        print "# 'ordered_classes' has not been modified. objectes updated previousely are still in that list"
146        # Now delete the actual data.
147        for cls in ordered_classes:
148            print 'Class: ',cls
149            items = obj_pairs[cls]
150            items.reverse()
151
152            pk_list = [pk for pk,instance in items]
153            del_query = sql.DeleteQuery(cls, connection)
154            del_query.delete_batch(pk_list)
155            print '  ',del_query
156            # Last cleanup; set NULLs where there once was a reference to the
157            # object, NULL the primary key of the found objects, and perform
158            # post-notification.
159            for pk_val, instance in items:
160                for field in cls._meta.fields:
161                    if field.rel and field.null and field.rel.to in seen_objs:
162                        setattr(instance, field.attname, None)
163                        print '  ','the object %s gets its %s set to None'%(instance,field.attname)
164
165                signals.post_delete.send(sender=cls, instance=instance)
166                print '  ',"post_delete signal sent"
167                setattr(instance, cls._meta.pk.attname, None)
168                print '  ','the object %s gets its %s set to None'%(instance,cls._meta.pk.attname)
169        if forced_managed:
170            transaction.commit()
171        else:
172            transaction.commit_unless_managed()
173    finally:
174        if forced_managed:
175            transaction.leave_transaction_management()
176    print "."*40
177           
Back to Top