Django,根据其他管理页面输入在保存期间自动设置字段
我正在寻找在 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 数据库,所以这不起作用,除非有人可以告诉我如何使用属性进行过滤。虽然我宁愿将值保存在数据库中。
我尝试了 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 更新为其他内容,例如附加表示当前日期的字符串,但我只是无法访问后缀。
谢谢,Dale
解决方案:
@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 次,但至少在最终运行中得到了正确的结果。
非常感谢丹尼和布尔汉
I'm looking for the correct way to set full_name in SuperPerson instance.
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 is hidden from the user on the Admin page, and is to be automatically be updated based on the other inputs on Admin page when the Admin page save button is hit.
I have tried overriding save like this and variations:
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)
This method works if I hit the save button in the Admin page twice, which is unacceptable for my use cases, seems like the new self.suffixes I have entered from the Admin page hasn't made it into database with the first super.save when I call self.suffixes.all().
I tried making full_name a property with decorator, but I also need to be able to filter Person and SuperPerson dbs using full_name, so that didn't work, unless someone can tell me how to filter with a property. Though I would rather have the value saved in the db.
I tried pre_save and post_save signals - neither worked.
@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__()
Edit: - this has same effect - the instance suffixes do not match what was in the Admin page.
What is the right way to save full_name based on other inputs? Oh and I'm hoping to avoid messing with Admin forms.
ADDITIONAL INFORMATION:
It seems the problem is specifically that the suffixes field is not being updated by the time I'm trying to use it. I can update full_name to something else, like appending a string representing the current date, I just cannot access the suffixes.
Thanks, Dale
SOLUTION:
@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()
I'm curious why I had to use Person.suffixes.through instead of SuperPerson, Suffixes or Person.suffixes - is there good documentation on this somewhere, I couldn't find it. And, it runs the code 4 times, but at least ends up with the correct result in the final run.
Many thanks to Danny and burhan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于您与 Suffix 的 m2m 关系,或者更确切地说,是 django admin 保存 m2m 关系的方式。
一个很好的解释是在这个答案中 为什么将站点添加到对象在 Django 管理中的 save() 覆盖中似乎不起作用?
当您通过管理表单保存模型时,它不是原子事务。首先保存主对象(以确保它具有 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
The problem is your m2m relationship with Suffix, or rather the way that django admin saves m2m relationships.
A pretty good explanation is in this answer to Why is adding site to an object doesn't seem to work in a save() override in the Django admin?
When you save a model via admin forms it's not an atomic transaction. The main object gets saved first (to make sure it has a PK), then the M2M is cleared and the new values set to whatever came out of the form.
post_save() is actually still too early. That's where the instance was saved, not its relationships.
You need to connect to the m2m_changed signal: https://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed
or wait for Django 1.4 where ModelAdmin gives you a "when all is done" signal:
https://code.djangoproject.com/ticket/16115