Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/105.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在保存模型之前检查ManytoMany是否有值?_Python_Django_Orm_Many To Many - Fatal编程技术网

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
,然后检查表单内部的内容。