0

the class:

class Operation(models.Model):
  related_operation = models.ForeignKey('self', null = True)

  __related_operation = None

  def __init__(self, *args, **kwargs):
    super(Operation, self).__init__(*args, **kwargs)
    self.__related_operation = self.related_operation

  def save(self, force_insert=False, force_update=False):
    if self.related_operation != self.__related_operation:
      del self.__related_operation

    super(Operation, self).save(force_insert, force_update)
    self.__related_operation = self.related_operation

the code:

 (...)
 OperationFormSet = modelformset_factory(Operation, form=OperationCategoryOnlyForm)
  if request.method == "POST":
    formset = OperationFormSet(request.POST, queryset=Operation.objects.filter(category=category_id))
    if formset.is_valid():
      instances = formset.save(commit = False)
      for instance in instances:
        if instance.related_account is not None:
          related_operation = Operation()
          related_operation.related_operation = instance
          related_operation.save()
          instance.related_operation = related_operation

        instance.save()

      formset = OperationFormSet(queryset=Operation.objects.filter(category=category_id))
  else:
    formset = OperationFormSet(queryset=Operation.objects.filter(category=category_id))

and the problem:

without the overwriting the method save everything works properly, but if i change related_operation in form, it of course makes second, third and so on related operation.

so i decided to overwrite the save method - and add the __related_operation. During saving it checks if related_operation changes - if so - it should delete the old related_operation and than save (with creating a completely new one related_operation)... And it almost works! (the new related_operation is added to database, but it loops after save. It never ends. I don't know what it is doing. I have to restart apache to get any answer from server. Maybe it's stupid mistyping or something very complex - i'm stacked...

(of course the operation class has more than one field e.g. related_account, so the if instance.related_account is not None: is correct)

UPDATE:

I found, that the problem is here:

def __init__(self, *args, **kwargs):
  super(Operation, self).__init__(*args, **kwargs)
  #self.__related_operation = self.related_operation

If i comment out the line above - everything goes ok - but of course it is wrong - why it blocks sth.

Tomasz Brzezina
  • 1,452
  • 5
  • 21
  • 44

2 Answers2

0

As far as I understand, you are trying to perform some kind of pre/post-save action. This begs for using Django's signals

For example in models.py

import django.db.models.signals.pre_save

def my_handler(sender, **kwargs):
  if not kwargs['instance'].related_operation:
    new_related_operation = Operation(related_operation = kwargs['instance'])
    new_related_operation.save() # this will cause calling signal again
    kwargs['instance'].related_operation = new_related_operation

pre_save.connect(my_handler, sender=Operation)

HTH

mhaligowski
  • 2,182
  • 20
  • 26
  • I take the example from http://stackoverflow.com/questions/1355150/django-when-saving-how-can-you-check-if-a-field-has-changed - here man wrote that overwritting is prefered over signalig – Tomasz Brzezina Sep 19 '12 at 05:08
0

I found where's the problem and found the solution...

I tried to link object of the same type in init - so during initialization I create another instance of the object so it creates another and another until it dies.

So the solution (for now - maybe someone presents best) is:

class Operation(models.Model):
  related_operation = models.ForeignKey('self', null = True)

  __related_operation = None

  def __init__(self, *args, **kwargs):
    super(Operation, self).__init__(*args, **kwargs)
    self.__related_operation = self.related_operation_id

  def save(self, force_insert=False, force_update=False):
    super(Operation, self).save(force_insert, force_update)
    if self.related_operation is not None:
      if self.related_operation_id != self.__related_operation:
        if self.__related_operation is not None:
         Operation.objects.get(id = self.__related_operation).delete()

    if self.related_operation is not None:
      self.__related_operation = self.related_operation_id

  def __unicode__(self):
    return str(self.id)

as you can see - now I use the id instead of object, so assignment doesn't fire the creation of object...

I think this can be helpful for someone else.

Tomasz Brzezina
  • 1,452
  • 5
  • 21
  • 44