Django ManyToMany与“自我"的关系而没有向后的关系 [英] Django ManyToMany relation to 'self' without backward relations

查看:91
本文介绍了Django ManyToMany与“自我"的关系而没有向后的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有一些关于向后关系的问题,但我要么太愚蠢而无法理解它们,要么认为它们不适合我的情况.

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.

我有模特

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:

表格:

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

所以当我显示对象first_related_object并检查与之的关系

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

所以我很想解释自己.

也许这段代码可以更好地说明我想要的东西.

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

现在唯一的问题是-如果我不希望它们产生结果,我是否应该甚至使用stuff.all(),并且应该编写自己的管理器/方法来获取不包含向后关系的对象列表.

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 针对亨利·弗洛伦斯:

edit2 In response to Henry Florence:

好的-我确实使用空基进行了测试,并且看起来对称= False确实存在数据库级别差异.我认为.

Okay - i did test it with empty base and it looks like symmetrical = False does have database level differences. I think.

我创建了一个对称= False的空表,然后创建添加关系并没有产生向后关系.如果我创建没有对称的空表= False.然后他们是.设置symmetrical = False不会导致创建AFTER表后的差异.因此,我认为差异在于数据库级别.

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 那我应该在这里做什么?

/edit2 So what am i supposed to do here?

写我自己的经理或其他东西吗?

Write my own manager or something?

艾伦

推荐答案

我对问题的理解是,ManyToMany关系应该是一种方式,如果满足以下条件,则是这样:

My understanding of the question is that the ManyToMany relationship should be one way, in that if the following is true:

             --------------           ----------------
             | mymodelone |---------->|  mymodeltwo  |
             --------------     |     ----------------
                                |
                                |     ----------------
                                ----->| mymodelthree |
                                      ----------------

然后在另一个方向上不应存在隐式关系:

Then there should not be an implicit relationship in the other direction:

             --------------           ----------------
             | mymodelone |<-----/----|  mymodeltwo  |
             --------------           ----------------

             --------------           ----------------
             | mymodelone |<-----/----| mymodelthree |
             --------------           ----------------

ManyToMany字段具有symmetrical属性,默认情况下为True,请参见:

ManyToMany fields have a symmetrical property which by default is True, see: here.

要创建一个新应用来演示非对称的ManyToMany字段,请执行以下操作:

To create a new app to demonstrate the non symmetric ManyToMany field:

创建一个新应用:

$ python ./manage.py startapp stuff

settings.py中添加东西应用:

...
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'stuff'
)
....

编辑`stuff/models.py:

edit `stuff/models.py:

from django.db import models

class MyModel(models.Model):
    stuff = models.ManyToManyField('self', related_name = 'combined+', symmetrical=False, blank = True, null = True, verbose_name = "description")

    def __unicode__(self):
        return "MyModel%i" % self.id

同步数据库:

$ python ./manage.py syncdb
Creating tables ...
Creating table stuff_mymodel_stuff
Creating table stuff_mymodel
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

然后在Django shell中进行测试:

and then test in the django shell:

$ python ./manage.py shell
>>> from stuff.models import MyModel
>>> MyModel().save()
>>> MyModel().save()
>>> MyModel().save()
>>> MyModel.objects.all()
[<MyModel: MyModel1>, <MyModel: MyModel2>, <MyModel: MyModel3>]
>>> m1 = MyModel.objects.get(pk=1)
>>> m2 = MyModel.objects.get(pk=2)
>>> m3 = MyModel.objects.get(pk=3)
>>> m1.stuff.all()
[]
>>> m1.stuff.add(m2)
>>> m1.stuff.add(m3)
>>> m1.stuff.all()
[<MyModel: MyModel2>, <MyModel: MyModel3>]
>>> m2.stuff.all()
[]
>>> m3.stuff.all()
[]
>>> 

编辑-现有模型上的ManyToMany关系

ManyToManyField的对称性是在将模型写入数据库时​​创建的,而不是在读取模型时创建的.如果我们将模型更改为:

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:

from django.db import models

class MyModel(models.Model):
    stuff = models.ManyToManyField('self', related_name = 'combined+')

def __unicode__(self):
    return "MyModel%i" % self.id

创建新的MyModel实例:

>>> MyModel().save()
>>> MyModel().save()
>>> MyModel.objects.all()
[<MyModel: MyModel1>, <MyModel: MyModel2>, <MyModel: MyModel3>, <MyModel: MyModel4>, <MyModel: MyModel5>]
>>> m4 = MyModel.objects.get(pk=4)
>>> m5 = MyModel.objects.get(pk=5)
>>> m4.stuff.add(m5)
>>> m4.stuff.all()
[<MyModel: MyModel5>]
>>> m5.stuff.all()
[<MyModel: MyModel4>]

与预期的一样,ManyToManyField东西正在创建对称关系.如果然后将ManyToManyField设置为symmetrical = False:

As expected the stuff ManyToManyField is creating symmetrical relations. If we then set the ManyToManyField to symmetrical = False:

>>> from stuff.models import MyModel
>>> MyModel().save()
>>> MyModel().save()
>>> MyModel.objects.all()
[<MyModel: MyModel1>, <MyModel: MyModel2>, <MyModel: MyModel3>, <MyModel: MyModel4>, <MyModel: MyModel5>, <MyModel: MyModel6>, <MyModel: MyModel7>]
>>> m6 = MyModel.objects.get(pk=6)
>>> m7 = MyModel.objects.get(pk=7)
>>> m6.stuff.all()
[]
>>> m7.stuff.all()
[]
>>> m6.stuff.add(m7)
>>> m6.stuff.all()
[<MyModel: MyModel7>]
>>> m7.stuff.all()
[]
>>> m5 = MyModel.objects.get(pk=5)
>>> m4 = MyModel.objects.get(pk=4)
>>> m4.stuff.all()
[<MyModel: MyModel5>]
>>> m5.stuff.all()
[<MyModel: MyModel4>]

可以看出,m6m7之间的新ManyToMany关系不是对称的,但是m4m5之间的现有关系仍然是对称的,就像创建这些对象时所说的模型一样

It can be seen the new ManyToMany relation between m6 and m7 is not symmetrical, however the existing one, between m4 and m5 is still symmetrical as the model stated when those objects were created.

编辑-具有对称外键的其他数据库约束

很抱歉给读者这么长时间的答案,我们似乎正在更深入地探讨这个问题.

Apologies to the reader to the length of this answer, we seem to be exploring this problem at some depth.

在sql中,通过创建一个表来建模多对多关系,该表包含该关系所独有的所有信息-通常仅是两个表的主键值.

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.

因此,对于我们的MyModel,django创建了两个表:

So for our MyModel, django creates two tables:

             -----------------           -----------------------
             | stuff_mymodel |---------->| stuff_mymodel_stuff |
             -----------------           -----------------------
                      ^                              |
                      |                              |
                      --------------------------------

图中显示的链接由模式中的主键或id值表示:

The links shown in the diagram are represented by primary key or id values within the schema:

mysql> describe stuff_mymodel;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.00 sec)

mysql> describe stuff_mymodel_stuff;
+-----------------+---------+------+-----+---------+----------------+
| Field           | Type    | Null | Key | Default | Extra          |
+-----------------+---------+------+-----+---------+----------------+
| id              | int(11) | NO   | PRI | NULL    | auto_increment |
| from_mymodel_id | int(11) | NO   | MUL | NULL    |                |
| to_mymodel_id   | int(11) | NO   | MUL | NULL    |                |
+-----------------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

并显示为Django manage.py脚本的输出:

And shown as the output from the Django manage.py script:

$ python ./manage.py sql stuff
    BEGIN;
CREATE TABLE `stuff_mymodel_stuff` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `from_mymodel_id` integer NOT NULL,
    `to_mymodel_id` integer NOT NULL,
    UNIQUE (`from_mymodel_id`, `to_mymodel_id`)
)
;
CREATE TABLE `stuff_mymodel` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY
)
;
ALTER TABLE `stuff_mymodel_stuff` ADD CONSTRAINT `from_mymodel_id_refs_id_7fa00238` FOREIGN KEY (`from_mymodel_id`) REFERENCES `stuff_mymodel` (`id`);
ALTER TABLE `stuff_mymodel_stuff` ADD CONSTRAINT `to_mymodel_id_refs_id_7fa00238` FOREIGN KEY (`to_mymodel_id`) REFERENCES `stuff_mymodel` (`id`);
COMMIT;

无论django ManyToManyField是否对称,此sql都是相同的.唯一的区别是在stuff_mymodel_stuff表中创建的行数:

This sql is the same irrespective if the django ManyToManyField is symmetrical or not. The only difference is the number of rows created in the stuff_mymodel_stuff table:

mysql> select * from stuff_mymodel_stuff;
+----+-----------------+---------------+
| id | from_mymodel_id | to_mymodel_id |
+----+-----------------+---------------+
|  1 |               1 |             2 |
|  2 |               1 |             3 |
|  3 |               4 |             5 |
|  4 |               5 |             4 |
|  5 |               6 |             7 |
+----+-----------------+---------------+
5 rows in set (0.00 sec)

链接m4 -> m5是对称的,其他链接不是对称的.如果symmetricalTrue:

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, if symmetrical is True:

    # If the ManyToMany relation has an intermediary model,
    # the add and remove methods do not exist.
    if rel.through._meta.auto_created:
        def add(self, *objs):
            self._add_items(self.source_field_name, self.target_field_name, *objs)

            # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
            if self.symmetrical:
                self._add_items(self.target_field_name, self.source_field_name, *objs)
        add.alters_data = True

当前在github上是第605行: https://github .com/django/django/blob/master/django/db/models/fields/related.py

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.

这篇关于Django ManyToMany与“自我"的关系而没有向后的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆