【问题标题】:Many - To - Many field changes - Too many api calls多对多字段更改过多的 api 调用
【发布时间】:2020-01-02 21:39:22
【问题描述】:

使用 Django,我遇到了多对多字段的已知问题。在 post_save_event 信号/挂钩中,多对多字段的 Event 实例中的值:类别不会使用管理表单上提交的最新值进行更新。它始终显示旧值。

这是我的保存挂钩,其中我有一个父“事件”,每个事件都有一个用于 0 或多个类别的字段。但是,instance.categories 值不会更新为最新值。

@receiver(post_save, sender=Event)
def post_save_event(sender, instance, **kwargs):
 success = events_api.create_or_update_event(instance)

我知道为什么会发生这种情况。基本上,多对多字段需要在父模型之后保存,因为多对多表需要有事件的主键。

我做了我在下面网上找到的修复。这是多对多表事务提交后发送的信号。

这种方法可以作为一种解决方法,但显然这意味着如果事件的类别发生变化,则 api 会被多次调用,更糟糕的是 m2m_changed 信号在发生时似乎会触发两次。所以我最终为一次更新调用了 3 次 api。

在成功保存表单而不是 post_save 事件之后,我可以使用任何解决方法/挂钩来执行此操作?

def category_has_changed(sender, **kwargs):
 logger.error("Inside: Inside category has changed")
 instance = kwargs.pop('instance')
 success = events_api.create_or_update_event(instance)

m2m_changed.connect(category_has_changed, sender=Event.categories.through)

events_api的相关部分:

def _create_or_update_event(event, mode):
    response = None
    try:
        headers = get_api_headers(event.cms_event_id)

        categories = []
        for cat in event.categories.all():
            categories.append(cat.id)
        # ISSUE: event.categories.all() does not contain the most recent updated array of categories

        # Basic event details.
        body = {
            'cms_event_id': str(event.cms_event_id),
            'categories': categories,
        }
        requests.post(ENDPOINT_CREATE_EVENT, json=body, headers=headers)

型号:

class Category(models.Model):
    name_en = models.CharField(
        _('Category name (English)'),
        blank=True, null=True, max_length=200,
        help_text=_('''
        Helpful details (for English language customers) about where the workshop is taking
         place, such as the location inside the store (ex. 2nd floor cafeteria).
        '''))
    name_fr = models.CharField(
        _('Category name (French)'),
        blank=True, null=True, max_length=200,
        help_text=_('''
        Helpful details (for English language customers) about where the workshop is taking
         place, such as the location inside the store (ex. 2nd floor cafeteria).
        '''))

    def __str__(self):
        return self.name_en

    class Meta:
        ordering = ('name_en',)
        verbose_name_plural = _('Categories')

class Event(Page):
    formfield_overrides = {
        models.ManyToManyField: {'widget': CheckboxSelectMultiple},
    }
    super_manager = models.Manager()

    ...

    categories = models.ManyToManyField(blank=True, null=True, to='Category')


【问题讨论】:

  • 您能否展示您的 Event 和 Category 模型以及您的 events_api(创建或更新方法),以便我们了解您想要做什么?您已经向我们介绍了您认为可能的解决方案,但并没有真正解释您想要做什么。
  • @dirkgroten 我更新了模型和类别 api 部分的问题。 api 调用本身不是问题,问题在于调用 api 发送具有过时类别的实例的信号。我添加了更新类别多对多表时的信号,并使用更新的类别再次调用 api,但是每当外键更改时必须调用 api 两次,这很愚蠢。我只是想知道是否有更好的钩子或信号。
  • 现在清楚了,谢谢,好问题!在将类别添加到事件时,您可能会循环访问它们,而不是调用 set() 立即更新它们。这就是为什么您会多次调用 m2m_changed。但是,是的,无论如何我都不会将它与 m2m_changed 信号挂钩,如果稍后删除一个类别会发生什么?这将为所有事件调用 m2m_changed,是否应该在您的 api 上再次创建事件?
  • 我想我找到了一种从表单传递值的方法。我会更新解决方案

标签: django django-models


【解决方案1】:

我能够像这样在我的 modelAdmin 中修改我的 save_model

class EventAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
    obj.new_categories = form.cleaned_data.get('categories')
    obj.save()

    super().save_model(request, obj, form, change)

然后在 signals.py 中我将它作为实例的一部分:

instance.new_category

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 2018-08-22
    • 2018-06-07
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多