![](/img/trans.png)
[英]How to make recursive ManyToManyField relationships that have extra fields symmetrical in Django?
[英]How to make a recursive ManyToMany relationship symmetrical with Django
我已經閱讀了關於 Django Docs 的symmetrical=True
。 我也讀過這個問題,對舊版本的 Django 提出了同樣的問題,但下面的代碼不像 Django 文檔描述的那樣工作。
# people.models
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=255)
friends = models.ManyToManyField("self",
through='Friendship',
through_fields=('personA', 'personB'),
symmetrical=True,
)
def __str__(self):
return self.name
class Friendship(models.Model):
personA = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='personA')
personB = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='personB')
start = models.DateField(null=True, blank=True)
end = models.DateField(null=True, blank=True)
def __str__(self):
return ' and '.join([str(self.personA), str(self.personB)])
如果bill
和ted
是朋友,我希望bill.friends.all()
包含ted
,而ted.friends.all()
包含bill
。 這不是發生的事情。 bill
的查詢包括ted
,但ted
的查詢不包括 bill 。
>>> from people.models import Person, Friendship
>>> bill = Person(name='bill')
>>> bill.save()
>>> ted = Person(name='ted')
>>> ted.save()
>>> bill_and_ted = Friendship(personA=bill, personB=ted)
>>> bill_and_ted.save()
>>> bill.friends.all()
<QuerySet [<Person: ted>]>
>>> ted.friends.all()
<QuerySet []>
>>> ted.refresh_from_db()
>>> ted.friends.all()
<QuerySet []>
>>> ted = Person.objects.get(name='ted')
>>> ted.friends.all()
<QuerySet []>
這是一個錯誤還是我誤解了什么?
編輯:更新代碼以顯示與through_fields
設置相同的行為。
添加關系的正確方法是bill.friends.add(ted)
。 這將使bill
與ted
成為朋友,並使ted
與bill
成為朋友。 如果您想為中間模型上的額外字段設置值,在我的情況下start
和end
,請使用add()
的through_defaults
參數。
...
>>> bill.friends.add(ted, through_defaults={'start': datetime.now()}
在某些情況下,您希望bill
-> ted
之間的關系在中間模型上具有與ted
-> bill
不同的值。 例如,當他們第一次見面時, bill
認為ted
很“酷”,但ted
認為bill
很“卑鄙”。 在這種情況下,您將需要輔助功能。
# people.models
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=255)
friends = models.ManyToManyField("self", through='Friendship')
def __str__(self):
return self.name
def add_friendship(self, person, impressionA, impressionB, recursive=True):
self.friends.add(person, through_defaults={'personA_impression': impressionA, 'personB_impression': impressionB)
if recursive:
person.add_friendship(self, impressionB, impressionA, False)
class Friendship(models.Model):
personA = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='a')
personB = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='b')
personA_impression = models.CharField(max_length=255)
personB_impression = models.CharField(max_length=255)
def __str__(self):
return ' and '.join([str(self.personA), str(self.personB)])
調用bill.friends.add(ted, through_defaults={"personA_impression": "cool", "personB_impression": "mean"})
結果如下:
...
>>> bill_and_ted = Friendship.objects.get(personA=bill)
>>> ted_and_bill = Friendship.objects.get(personA=ted)
>>> bill_and_ted.personA_impression
"cool" # bill thinks ted is cool
>>> bill_and_ted.personB_impression
"mean" # ted thinks bill is mean
>>> ted_and_bill.personA_impression
"cool" # ted thinks bill is cool. This contradicts the bill_and_ted intermediate model
使用add_friendship
函數為字段分配適當的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.