nven
nven

Reputation: 1227

Django ORM and pre_init signal

I have a class which has two children

class MyChild1(models.Model):
    attr1 = models.CharField(default='default value')

class MyChild2(models.Model):
    pass

class MyParent(models.Model):
    child1 = models.ForeignKey(Child1)
    child2 = models.ForeignKey(Child2)

In my package, I require the value of attr1 - and in order to make sure it exists, I initialize the parent with a signal:

def init_my_parent(sender, *args, **kwargs):
    child1 = MyChild1()
    child2 = MyChild2()

signals.pre_init.connect(init_my_parent,sender=MyParent)

This seems to work fine to ensure that child1 and child2 are always instantiated. However, even when I manually set child1 and child2 (my_parent.child1 = child1 etc), child1_id and child2_id do not get set and the db throws an error

django.db.utils.IntegrityError: NOT NULL constraint failed: myparent.child1

I'm wondering what is causing this behavior? Somehow connecting that signal is causing a problem, but I'm not sure why. Here is a script similar to what I'm using:

c1 = MyChild1()
c2 = MyChild2()
c1.save()
c2.save()
p = MyParent()
p.child1 = c1
p.child2 = c2
p.save()
# Error thrown

Both of the values set in init_my_parent should be overwritten above, and thus everything should work the same as if the signal function wasn't there?

Upvotes: 0

Views: 765

Answers (2)

Domen Blenkuš
Domen Blenkuš

Reputation: 2242

The problem is that pre_init signal doesn't take instance parameter, so you are editing actual class (sender). Try using post_init signal which takes instance parameter, so you can change it:

def init_my_parent(sender, instance, *args, **kwargs):
    if not hasattr(instance,'child1'): 
        instance.child1 = MyChild1()
        instance.child1.save()
    if not hasattr(instance,'child2'): 
        instance.child2 = MyChild2()
        instance.child2.save()

signals.post_init.connect(init_my_parent, sender=MyParent)

Upvotes: 1

Lawes
Lawes

Reputation: 14

class MyChild1(models.Model):
    attr1 = models.CharField(default='default value', max_length=100)

class MyChild2(models.Model):
    pass

class MyParent(models.Model):
    child1 = models.ForeignKey(MyChild1)
    child2 = models.ForeignKey(MyChild2

using class instead of def, then it is going to be fine.

Upvotes: 0

Related Questions