django为在foreignkey字段模型中创建的新实例自动创建中间模型实例

时间:2015-08-29 16:01:23

标签: django instances manytomanyfield

以下情况有两个部分:

我将用例子来描述这个问题:

这些是我的django模型:

class Zone(models.Model):
    zone_name = models.CharField(max_length = 10)
    zone_number = models.CharField(max_length = 10)

    class Meta:
        ordering = ('zone_name',)      

    def __unicode__(self):
        return self.zone_name  


class Stage(models.Model):
    stage_number = models.CharField(max_length = 10)
    stage_name = models.CharField(max_length = 10)
    zones = models.ManyToManyField(Zone, through='ZoneStage')

    class Meta:
        ordering = ('stage_number',)      

    def __unicode__(self):
        return self.stage_number  

    @property
    def value(self):
        return ZoneSubStage.objects.filter(substage__stage=self).aggregate(Sum('value')).get('value__sum', 0)  


class ZoneStage(models.Model):
    zone = models.ForeignKey(Zone)
    stage = models.ForeignKey(Stage)
    value = models.PositiveSmallIntegerField(default=0)

    class Meta:
        ordering = ('zone',)          

    def __unicode__(self):
        return '%s %s' % (self.zone, self.stage)

class SubStage(models.Model):
    sub_name = models.CharField(max_length=10)
    stage = models.ForeignKey(Stage)
    zones = models.ManyToManyField(Zone, through='ZoneSubStage')

    def __unicode__(self):
        return self.sub_name


class ZoneSubStage(models.Model):
    zone = models.ForeignKey(Zone)
    substage = models.ForeignKey(SubStage)
    value = models.PositiveSmallIntegerField(default=0)

    def __str__(self):
        return '%s %s' % (self.zone, self.substage)  

问题1: 如果我手动创建新的Zone实例,如何为所有相关阶段自动创建新的ZoneStage实例?

e.g。我有以下Stage实例:S1,S2,S3,S4和我创建新的Zone实例“A”。那么,我想自动创建新的ZoneStage实例AS1,AS2,AS3,AS4如果这样的实例已经不存在了吗?

问题2: 这是问题1的扩展。如果我创建新区域,我想按照问题1中的描述自动创建ZoneStage实例,如果此类ZoneSubStage实例尚未存在,我想为所有阶段中的所有子阶段自动创建ZoneSubStage实例。

我不知道如何开始。我可能先读一下post_save()吗?

2 个答案:

答案 0 :(得分:0)

子回答: 首先,您不希望在类ZoneStage中添加zone = models.ForeignKey(Zone),因为您的信息包含stage = models.ForeignKey(Stage);

问题1: 你可以像这样在创建阶段后截取信号(post_save)。

@receiver(post_save, sender=Stage)
def gen_coupon(sender, instance, raw=True, **kwargs):
    new_zone_stage = ZoneStage(stage=instance)
    new_zone_stage.save()
    return kwargs

问题2:相同的逻辑,但您将发件人更改为当前创建的模型对象

答案 1 :(得分:0)

我已阅读有关我的问题并从django手册中收集了一些知识。拉克温的建议指引我走向正确的方向。这就是我所拥有的,目前正在发挥作用。虽然,我不检查这样的实例是否已经存在。此外,我已经阅读了两个django,除非真的有必要,否则使用信号并不好。我应该使用模型管理器。

我创建了文件 signals.py 并将其存储在models.py旁边的app文件夹中。它包含以下代码:

from django.dispatch import Signal


def create_new_zonestage_if_new_zone(sender, **kwargs):
    if kwargs.get('created',False):
        from models import Stage, ZoneStage
        stages = Stage.objects.all()
        for mystage in stages: 
            ZoneStage.objects.get_or_create(stage=mystage,zone=kwargs.get('instance'))
    return kwargs

def create_new_zonesubstage_if_new_zone(sender, **kwargs):
    if kwargs.get('created',False):
        from models import SubStage, ZoneSubStage
        substages = SubStage.objects.all()
        for mysubstage in substages: 
            ZoneSubStage.objects.get_or_create(substage=mysubstage,zone=kwargs.get('instance'))
    return kwargs

我在 models.py

中添加了以下内容

以上模型类:

from django.db.models.signals import post_save
from . import signals

以下模型类:

post_save.connect(signals.create_new_zonestage_if_new_zone, sender=Zone)
post_save.connect(signals.create_new_zonesubstage_if_new_zone, sender=Zone)

它有效。