如何在保存Model之前检查ManytoMany是否有值?

时间:2016-06-02 05:27:58

标签: python django orm many-to-many

假设我有两个类/模型:HandFinger。想象一下,models.py中的指纹是一个TextField而一个Hand有一个未知数量的手指:

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']}]

保存Hand时,我们需要检查初始化时有多少手指与手相关。并且还可以访问Finger模型中的is_a_thumb字段来填充/关联来自Hand的has_a_thumb

  • 如何从每个is_a_thumb访问Finger,以便如果有一个手指is_a_thumb,则会更改Hand的{​​{1}}值保存前has_a_thumb

  • 如何访问号码。已分配给Finger的{​​{1}},以便我可以在保存之前更新Hand

3 个答案:

答案 0 :(得分:1)

This是关于使用ManyToMany字段的django文档。和this m2m_changed信号的文档。我想你应该在这里使用它。我从来没有在实践中使用过这个信号,但据我所知,代码应该是这样的。

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时你的代码有错误。在这个例子中,你应该使用Hand而不是Sentence。

答案 1 :(得分:1)

我不确定你是否可以这样做before你的对象得到了保存。而且我认为这不是正确的方法。我相信你需要做的就是倾听m2m_changed信号并更新你的手。

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是否是正确的关系。是的,一只手可以有很多手指,但一根手指应该只属于一只手?如果那是真的那么你需要将关系改为一对多(手指有一个FK手指)。

答案 2 :(得分:0)

您可以使用hand.fingers.count()来了解对象的手指数量。