views:

35

answers:

3

I have the following model:

One
   name (Char)

Many
    one (ForeignKey,blank=True,null=True)
    title (Char)

I want to delete a One instance and all related objects should loose their relation to the One instance. At the moment my code looks like this:

one=One.objects.get(<some criterion>)

more=Many.objects.filter(one=one)
for m in more
    m.one=None
    m.save()
#and finally:
one.delete()

what does the code do? It finds the object, that should be deleted then searches for related objects, sets their ForeignKey to None and finally deletes the One instance. But somewhere in that process it also manages to kill all related objects (Many instances) in the process. My question is: Why are those related objects deleted and how do I prevent this?

A: 

Hi

Why: The reason why it deletes it is because of "ForeignKey". It means, "name" of "One" is a key in "Many". So if you delete a "One" then some of the "Many" lose their keys. Since you cannot have an object without a primary key (in this case your foreign key) they are deleted.

How to prevent: Don't use a ForeignKey. If there can be a "Many" object without having a corresponding "One" object then you shouldn't have a ForeignKey to them. Just use a normal primary key.

Hope this helps.

Paul the n-th
Do I get you right? Are you saying that a foreign-key field is meant to model a 1-1 reationship? how can i have serveral 'many's with the same 'one' then?
niklasfi
No it's not meant to model a 1:1 relationship. Sorry if my answer wasn't clear.In your "Many" model you say "ForeignKey". This is a type of key. So every row in that table has to have this key. In your code you set this field to None (m.one=None). I'm not sure how this code can run but I assume that after you none-ify the key of a row that row gets deleted!If you want many "Many"s to have the same "One", then leave the model as it is. What you cannot have is a "Many" that does not have a "One"!
Paul the n-th
I found out it does work. My problem was a typo in my implementation this rendered the (m.one=None) useless. The code in the question is correct!
niklasfi
+1  A: 

You can use bunch update in first place:

Many.objects.filter(one=one).update(one=None)

I think that Django deletes related object on program level (without on delete cascade in DBMS). So probably your objects are in some kind of cache and Django still thinks that they are related to one object.

Try to list related objects before you delete.

print one.many_set
one.delete()

If you still have any objects in this set you probably should fetch one from DB again, and then delete. Or you can use bunch delete:

One.objects.filter(<cryteria>).delete()
Tomasz Wysocki
A: 

The code given is correct. My problem when asking the question was a typo in my implementation.

shame on me

well... there is still a bit that could be improved on:

more=Many.objects.filter(one=one)
for m in more
    m.one=None
    m.save()
#and finally:
one.delete()

can be written as:

for m in one.many_set.all()
    m.one=None
    m.save()
one.delete()

which is equivalent to:

one.many_set.clear()
one.delete()
niklasfi