Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__init__ called when calling filter on foreign key concatenation

I'm really baffled by this one:

I have 3 models, chained together by foreign keys:

from django.db import models

class A(models.Model):
  name = models.CharField(max_length=100, unique=True)

class B(models.Model):
  a = models.ForeignKey(A)
  name = models.CharField(max_length=100, unique=True)

class C(models.Model):
  b = models.ForeignKey(B)
  name = models.CharField(max_length=100, unique=True)      

  def __init__(self, *args, **kwargs):
    import pdb; pdb.set_trace()
    super(C, self).__init__(*args, **kwargs)
    self.name = 'inited'

When I try to get a list of all instances of C that point to a certain instance of A, C's __init__ gets called:

class SimpleTest(TestCase):
  def test_goes_to_init(self):
    a = A(name = 'a')
    a.save()
    b = B(name = 'b', a = a)
    b.save()
    c = C(name = 'c', b = b)
    c.save()
    cs = C.objects.all().filter(b__a=a)
    arr = [i for i in cs] # Here C's __init__ gets called
    self.assertEqual(arr.__len__(), 1)

Why should that be? Is there a way for generating the array w/o calling __init__? In my real application the __init__ function is very slow, and should be called rarely.

Here's the back trace from the debugging session:

  /home/ranmoshe/sites/django/testttt/testing123/tests.py(13)test_goes_to_init()
-> arr = [i for i in cs]
  /usr/local/lib/python2.6/dist-packages/django/db/models/query.py(106)_result_iter()
-> self._fill_cache()
  /usr/local/lib/python2.6/dist-packages/django/db/models/query.py(760)_fill_cache()
-> self._result_cache.append(self._iter.next())
  /usr/local/lib/python2.6/dist-packages/django/db/models/query.py(282)iterator()
-> obj = self.model(*row[index_start:aggregate_start])
> /home/ranmoshe/sites/django/testttt/testing123/models.py(16)__init__()
-> super(C, self).__init__(*args, **kwargs)
like image 929
Ran Moshe Avatar asked Mar 21 '26 20:03

Ran Moshe


1 Answers

__init__ will be called each time the python instance is created. You are probably trying to execute the code when the database record is saved. For this, you should override your model's save() method:

class C(models.Model):
    ...

    def save(self, *args, **kwargs):
        do_something()
        super(C, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()
like image 94
Udi Avatar answered Mar 24 '26 09:03

Udi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!