There are several question about backwards relations here, but I'm either too dumb to understand them or think they don't fit my case.
I have model
class MyModel(models.Model)
stuff = models.ManyToManyField('self', related_name = 'combined+')
I have created form where i combine the information stored. And it stores object relations in database like that:
Table:
id:from_stuff_id:to_stuff_id
1:original_object_id:first_related_object
2:original_object_id:second_related_object
3:first_related_object:original_object_id
4:second_related_object:original_object_id
So when i display object first_related_object and check for relations with
myobject.stuff.all()
Then i get the "original_object". But i do not need it. I wish it would show no backwards relation like that.
Edit1
So i suck at explaining myself.
Perhaps this code will better illustrate what i want.
myobjectone = MyModel.objects.get(pk = 1)
myobjecttwo = MyModel.objects.get(pk = 2)
myobjectthree = MyModel.objects.get(pk = 3)
myobjectone.stuff.add(myobjecttwo)
myobjectone.stuff.add(myobjectthree)
myobjectone.stuff.all()
[myobjecttwo, myobjectthree] <-- this i want
myobjecttwo.stuff.all()
[myobjectone]<-- this i do not want
myobjectthree.stuff.all()
[myobjectone]<-- this i do not want
Now only question is - if i should even use stuff.all() if i dont want the results they yield and should write my own manager/methods to get list of objects which excludes backward relations.
/edit1
edit2 In response to Henry Florence:
Okay - i did test it with empty base and it looks like symmetrical = False does have database level differences. I think.
I created empty table with symmetrical = False, then creating adding relations did not spawn backwards relations. If i created empty table without symmetrical = False. Then they were. Setting symmetrical = False makes no difference AFTER tables have been created. So i guess the differences are on database level.
/edit2 So what am i supposed to do here?
Write my own manager or something?
Alan
My understanding of the question is that the ManyToMany relationship should be one way, in that if the following is true:
Then there should not be an implicit relationship in the other direction:
ManyToMany
fields have asymmetrical
property which by default isTrue
, see: here.To create a new app to demonstrate the non symmetric ManyToMany field:
Create a new app:
Add stuff app in
settings.py
:edit `stuff/models.py:
Sync the db:
and then test in the django shell:
Edit - ManyToMany relationship on existing models
The symmetry of the
ManyToManyField
is created when the models are written to the database, rather than when they are read. If we alter the model to:Create new
MyModel
instances:As expected the stuff
ManyToManyField
is creating symmetrical relations. If we then set theManyToManyField
tosymmetrical = False
:It can be seen the new
ManyToMany
relation betweenm6
andm7
is not symmetrical, however the existing one, betweenm4
andm5
is still symmetrical as the model stated when those objects were created.Edit - additional database constraints with a symmetrical foreign key
Apologies to the reader to the length of this answer, we seem to be exploring this problem at some depth.
In sql a many to many relation is modeled by creating a table that holds all the information unique to the relation - usually just the primary key value of the two tables.
So for our
MyModel
, django creates two tables:The links shown in the diagram are represented by primary key or id values within the schema:
And shown as the output from the Django
manage.py
script:This sql is the same irrespective if the django
ManyToManyField
is symmetrical or not. The only difference is the number of rows created in thestuff_mymodel_stuff
table:The link
m4 -> m5
being symmetrical and the others not. Digging around in the Django source we can find the code responsible for creating the 'mirror' entry in the sql, ifsymmetrical
isTrue
:This is currently line 605 on github: https://github.com/django/django/blob/master/django/db/models/fields/related.py
Hope this answers all your queries.