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 模型字段只读或在管理员中禁用