Python 如何在保存模型之前检查ManytoMany是否有值?
假设我有两个类/模型:Python 如何在保存模型之前检查ManytoMany是否有值?,python,django,orm,many-to-many,Python,Django,Orm,Many To Many,假设我有两个类/模型:Hand和Finger。假设指纹是一个文本字段,一只手有未知数量的手指,在models.py中: from django.db import models class Hand(models.Model): smoothness = models.IntegerField(default=0, validators=[ MaxValueValidator(5), MinValueValidator(0
Hand
和Finger
。假设指纹是一个文本字段,一只手有未知数量的手指,在models.py中:
from django.db import models
class Hand(models.Model):
smoothness = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0)
])
fingers = models.ManyToManyField('Finger')
num_fingers = models.IntegerField(default=0)
has_thumb = models.BooleanField(default=False)
def save(self, *args, **kwargs):
self.num_fingers = check_num_finger() # How do I do that?
if check_has_thumb(): # How do I do that?
self.has_thumb = True
super(Hand, self).save(*args, **kwargs)
class Finger(model.Model):
is_a_thumb = models.BooleanField(default=False)
fingerprint = models.TextField()
通过admin.py
添加新手,如下所示:
from django.contrib import admin
from .models import Hand, Finger
@admin.register(Finger)
class FingerAdmin(admin.ModelAdmin):
fieldsets = [('Finger', {'fields': ['is_a_thumb','fingerprint']})]
list_display = ('is_a_thumb', 'fingerprint',)
@admin.register(Hand)
class HandAdmin(admin.ModelAdmin):
fieldsets = [('Hand', {'fields': ['smoothness']},
('Fingers', {'fields': ['fingers']}]
当保存手时
,我们需要检查初始化时有多少手指与手相关。还可以访问手指模型内的is a_thumb
字段,以从手上填充/关联has a_thumb
- 如何从每个
手指
访问是拇指
,这样,如果有一个手指是拇指
,它会在保存之前更改手的有拇指
值
- 如何访问分配给
手的手指的数量,以便在保存之前更新手指的数量?
是django关于处理许多字段的文档。以及m2m_变更信号的文件。我想你应该在这里用。我从未在实践中使用过这个信号,但据我所知,代码应该是这样的
from django.db import models
from django.db.models.signals import m2m_changed
class Hand(models.Model):
smoothness = models.IntegerField(default=0,
validators=[
MaxValueValidator(5),
MinValueValidator(0)
])
fingers = models.ManyToManyField('Finger')
num_fingers = models.IntegerField(default=0)
has_thumb = models.BooleanField(default=False)
class Finger(model.Model):
is_a_thumb = models.BooleanField(default=False)
fingerprint = models.TextField()
def fingers_changed(sender, **kwargs):
instance = kwargs.pop('instance', None)
instance.num_fingers = instance.fingers.count()
if instance.fingers.filter(is_a_thumb=True):
instance.has_thumb = True
instance.save()
m2m_changed.connect(fingers_changed, sender=Hand.fingers.through)
顺便说一句,我认为在save方法中调用super时代码中有错误。在本例中,您应该使用手而不是句子。我不确定您是否可以在保存对象之前执行。我认为这不是正确的方法。我相信你需要做的是倾听信号并更新你的手
from django.db.models.signals import m2m_changed
def fingers_changed(sender, **kwargs):
#sender Hand.fingers.through (the intermediate m2m class)
#instance hand (the Hand instance being modified)
#action "pre_add" (followed by a separate signal with "post_add")
#reverse False (Hand contains the ManyToManyField, so this call modifies the forward relation)
#model Finger (the class of the objects added to the Hand)
#pk_set finger_ids beign added (when post_add its a set of all, not the new ones only, but all)
#using "default" (since the default router sends writes here)
if kwargs['action'] == 'post_add':
hand = kwargs['instance']
hand.num_fingers = hand.fingers.count() #or len(kwargs['pk_set'])
hand.has_thumb = hand.fingers.filter(is_a_thumb=True).exists()
hand.save()
m2m_changed.connect(fingers_changed, sender=Hand.fingers.through)
注意:顺便说一句,我不确定这里的M2M关系是否正确。是的,一只手可以有许多手指,但一个手指应该只属于一只手?如果这是真的,那么mb您需要将关系更改为一对多(手指上有一个FK)。您可以使用Hand.fingers.count()
来了解对象的手指数。self.fingers.count()
不起作用,它会遇到值错误。如果在保存之前没有Hand
的实例,self.fingers
将抛出一个ValueError
,即ValueError:“需要为字段“hand”设置一个值才能使用此多对多关系。
在链接的文档中,hand
在对象.relatedfield.count()之前保存一次后,已经存在于数据库中
works=(是的,这是我的错误。我使用m2m_changed signal更新了我的代码。谢谢Eduard!signal documentation链接很有用。谢谢,这很有效!但是一直保持信号并检查手是否被保存是一项非常昂贵的操作吗?是否只有在hand.save()时才有办法检查这一点
被称为?AFAIK,Hand.save()
没有访问M2M关系的权限,只有表单
有权限。因此另一种方法是设置form.save()
,使用commit=False
,然后检查表单内部的内容。