为什么在Django管理员的save()覆盖中添加一个对象的站点似乎不起作用? [英] Why is adding site to an object doesn't seem to work in a save() override in the Django admin?

查看:161
本文介绍了为什么在Django管理员的save()覆盖中添加一个对象的站点似乎不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经覆盖了我的一个模型的 save()方法,所以它可以继承自 sites object 和来自其父级的标签。

I have overrided the save() method of one of my model so it can inherit from the sites object and tags from its parent.

def save(self, *args, **kwargs):

    ret = models.Model.save(self, *args, **kwargs)

    if self.id:

        for site in self.parent.sites.all():
            self.sites.add(site.id)

        for tag in self.parent.tags_set.all():
            Tag.objects.add_tag(self, tag)

使用 ipdb ,我可以看到 self.sites.all()返回4个站点在最后的方法,但奇怪的是,一旦请求完成,相同的 self.sites.all()不再返回任何东西。

Using ipdb, I can see that self.sites.all() DOES return 4 sites at the end of the method, but strangely, once the request is finish, the same self.sites.all() does not return anything anymore.

我不使用交易(至少明确),我使用的是Django 1.3和Ubuntu 11.04

I don't use transactions (at least explicitly), and I'm using Django 1.3 and Ubuntu 11.04

编辑:发现它有效一个nywhere但在管理。管理电话没有保存吗?如果没有,我如何钩住对象创建/更新?

found out that it works anywhere but in the admin. Doesn't the admin call save? If not, how can I hook to the object creation / update?

EDIT2:测试,并且调用保存。我有打印声明来证明它。但它不会添加网站。这是一个谜。

tested, and does call save. I have print statements to prove it. But it doesn't add the sites. It's a mystery.

推荐答案

事实上,这是一个问题,当您使用Django管理员。

In fact, this is a problem about adding programatically many to many relationships when saving a model if you use the Django admin.

Django通过调用清除来清除管理员中的m2m关系,然后重新设置。这意味着该格式会将任何附加的数据(包括您的编程附加)存储到对象中,然后添加您在管理员中输入的数据。

Django save m2m relationships in the admin by calling 'clear' to wipe them out, then setting them again. It means that the form destroy any attached data (including your programatically attached) to the object then add the ones you entered in the admin.

它在管理外部工作,因为我们不要使用清除m2m关系的管理表单。

It works outside the admin because we don't use the admin form that clear the m2m relationship.

管理员中标签的原因是标记应用程序不使用m2m,而是模拟它通过将具有外键的TaggedItem对象放置到标签和使用通用关系的模型。此外,它是一个内联字段包含。

The reason it works for tags in the admin is that the tagging application doesn't use m2m but emulate it by placing a TaggedItem object with a foreign key to a tag and to your model with a generic relation. Plus it's an inline field inclusion.

我尝试了很多东西,最后不得不看看Django源代码,意识到Django不会在通常的过程中处理管理表单办法。它的作用是:

I tried a lot of things and finally had to look at the Django source code to realize that Django does not process admin forms in the usual way. What it does it:


  1. 调用 ModelAdmin.save_form :它调用 form.save with commit = False ,返回一个未保存的实例并添加一个 save_m2m 方法到表单

  2. 调用 ModelAdmin.save_model 实际调用实例 save 方法。

  3. 调用 form.save_m2m

  1. call ModelAdmin.save_form: it calls form.save with commit = False, returning an unsaved instance and adding a save_m2m method to the form.
  2. call ModelAdmin.save_model that actually calls the instance save method.
  3. call form.save_m2m

因此:


  • 您不能覆盖 save 方法,因为 save_m2m 被调用并清除m2m关系。

  • 你不能覆盖 save_model 由于同样的原因。

  • 您不能覆盖 save_m2m ,因为它是由猴子补丁添加到在 form.save 中的表单模型,删除您自己的方法定义。

  • you can't override your save method since save_m2m is called after and clear the m2m relations.
  • you can't override save_model for the same reason.
  • you can't override save_m2m because it is added by monkey patch to the form model in form.save, erasing you own method definition.

I没有找到一个干净的解决方案,但有用的是:

I didn't find a clean solution, but something that works is:

为ModelAdmin类提供一个表单方法用您自己的方法覆盖 save_m2m

Provide a form for the ModelAdmin class with a method to override save_m2m with your own method:

class MyModelForm(forms.ModelForm):

    class Meta:
        model = MyModel

    def set_m2m_method(self, update_tags_and_sites=True):

        alias = self.save_m2m

        def new_save_m2m(): # this is your new method 
            alias() # we need to call the original method as well
            self.instance.add_niche_sites_and_tags()

        self.save_m2m = new_save_m2m # we erase Django erasing :-)

ModelAdmin.model_save 中调用此方法覆盖:

class MyModelAdmin(admin.ModelAdmin):

    form = MyModelForm

    def save_model(self, request, obj, form, change):
        obj.save()
        form.set_m2m_method()

导致以下原因:


  1. Django调用 sa ve_model ,用你的代替它的猴子补丁

  2. django调用我们的 form.save_m2m ,首先调用它的旧清除关系的方法,然后将m2m附加到对象。

  1. Django calls save_model, replacing its monkey patch by yours
  2. django calls our form.save_m2m that first call its old method that clears relations, then attach the m2m to the object.

我完全可以使用更好的方法来做到这一点被扭曲而简单的丑陋。

I'm completely open to any better way to do this as this is twisted and plain ugly.

这篇关于为什么在Django管理员的save()覆盖中添加一个对象的站点似乎不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆