Django,在保存期间自动设置字段,基于其他管理页面输入

Posted

技术标签:

【中文标题】Django,在保存期间自动设置字段,基于其他管理页面输入【英文标题】:Django, auto setting a field during a save, based on other Admin page inputs 【发布时间】:2011-12-11 03:10:30 【问题描述】:

我正在寻找在 SuperPerson 实例中设置 full_name 的正确方法。

class Suffix(models.Mode):
    suffix = models.CharField(max_length=255)
    def __unicode__(self):
        return u'%s'%(self.suffix)

class Person(models.Model):
    first_name= models.CharField(max_length=255)
    last_name= models.CharField(max_length=255)
    suffixes= models.ManyToManyField(Suffix, blank=True, null=True)
    full_name= models.CharField(max_length=255)

class SuperPerson(Person):
    ignore_this_field= model.CharField(max_length=255)

full_name 在管理页面对用户隐藏,当点击管理页面保存按钮时,将根据管理页面上的其他输入自动更新。

我尝试过像这样覆盖保存和变体:

def save(self, *args, **kwargs):
    # Attempt to get data into the database so I can access it
    super(SuperPerson,self).save(*args,**kwargs)

    self.full_name = self.first_name + self.last_name 
    for suf in self.suffixes.all():
        self.full_name+= suf.__unicode__()

    # Now save the copy with full_name set as I wish
    super(SuperPerson,self).save(*args,**kwargs)

如果我两次点击管理页面中的保存按钮,此方法有效,这对于我的用例来说是不可接受的,似乎我从管理页面输入的新 self.suffixes 没有第一次进入数据库当我调用 self.suffixes.all() 时 super.save。

我尝试使用装饰器使 full_name 成为属性,但我还需要能够使用 full_name 过滤 Person 和 SuperPerson dbs,所以这不起作用,除非有人可以告诉我如何使用属性进行过滤。虽然我宁愿将值保存在数据库中。

我尝试了 pre_save 和 post_save 信号 - 都没有用。

@receiver(pre_save, sender=SuperPerson)
def set_full_name(sender, instance, **kwargs):
    instance.full_name = instance.first_name + instance.last_name

    for suf in instance.suffixes.all():
        instance.full_name+= ', ' + suf.__unicode__()

编辑: - 这具有相同的效果 - 实例后缀与管理页面中的内容不匹配。

根据其他输入保存 full_name 的正确方法是什么?哦,我希望避免弄乱管理表单。

附加信息: 问题似乎特别是在我尝试使用后缀字段时没有更新它。我可以将 full_name 更新为其他内容,例如附加代表当前日期的字符串,但我无法访问后缀。

谢谢,戴尔

解决方案:

@receiver(m2m_changed, sender=Person.suffixes.through)
def set_full_name_after_ManyToMany_saved(sender, instance, **kwargs):
    instance.full_name = instance.first_name + instance.last_name
    for suf in instance.suffixes.all():
        instance.full_name+= ', ' + suf.__unicode__()
    print 'Saving As', instance.full_name
    instance.save()

我很好奇为什么我必须使用 Person.suffixes.through 而不是 SuperPerson、Suffixes 或 Person.suffixes - 是否有关于这方面的好文档,我找不到。而且,它运行了 4 次代码,但至少在最终运行中得到了正确的结果。

非常感谢 Danny 和 burhan

【问题讨论】:

您的代码将pre_save绑定到SuperPerson,它应该绑定到Person 直接绑定到 Person 时代码永远不会运行,但请参阅我上面的评论。 【参考方案1】:

问题在于您与 Suffix 的 m2m 关系,或者更确切地说是 django admin 保存 m2m 关系的方式。

对Why is adding site to an object doesn't seem to work in a save() override in the Django admin?的回答中有一个很好的解释

当您通过管理表单保存模型时,它不是原子事务。首先保存主对象(以确保它具有 PK),然后清除 M2M 并将新值设置为表单中出现的任何值。

post_save() 实际上还为时过早。那是保存实例的地方,而不是它的关系。

需要连接m2m_changed信号:https://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed

或者等待 Django 1.4,ModelAdmin 会给你一个“当一切都完成”的信号: https://code.djangoproject.com/ticket/16115

【讨论】:

谢谢你,“当一切都完成后”的票永远不会新鲜。

以上是关于Django,在保存期间自动设置字段,基于其他管理页面输入的主要内容,如果未能解决你的问题,请参考以下文章

在 Django CharFields 中自动截断 max_length 字段

从 Django 中的文本字段填充管理表单

Django Mysql数据库-基于双下划线的跨表查询

在第一次保存对象时使 django 模型字段只读或在管理员中禁用

InterfaceError:错误绑定参数5 ... Django JWT令牌(django请求令牌工具)

Django之ORM查询进阶