python - 为外键字段创建 post_save 信号
问题描述
我有一个档案模型,其中包含经验和教育作为外键领域。当我访问配置文件模板时,它会抛出。
我试过post_save,
def create_education(sender, instance, created, **kwargs):
if created:
Profile.objects.create(education=instance)
post_save.connect(create_education, sender=CustomUser)
它抛出这个错误,
如何定义 post_save 信号,以便在创建配置文件时创建经验和教育?
注意:我仔细检查了错误是因为外部字段为空,即我在 django admin 中添加经验和教育字段时没有错误。
模型.py
class Work_Experience(models.Model):
job_title = models.CharField(max_length=100, null=True, blank=True)
company = models.CharField(max_length=100, null=True, blank=True)
description = models.CharField(max_length=300, null=True, blank=True)
exp_start_date = models.DateField(null=True, blank=True)
exp_end_date = models.DateField(null=True, blank=True)
class Education(models.Model):
degree = models.CharField(max_length=100, null=True, blank=True)
school = models.CharField(max_length=100, null=True, blank=True)
edu_start_date = models.DateField(null=True, blank=True)
edu_end_date = models.DateField(null=True, blank=True)
class Profile(models.Model):
experience = models.ForeignKey(Work_Experience, on_delete=models.SET_NULL, null=True, blank=True)
education = models.ForeignKey(Education, on_delete=models.SET_NULL, null=True, blank=True)
表格.py
class ProfileSettingsForm(forms.ModelForm):
job_title = forms.CharField(max_length=40, required=False)
company = forms.CharField(max_length=40, required=False)
description = forms.CharField(max_length=40, required=False)
exp_start_date = forms.DateField(required=False)
exp_end_date = forms.DateField(required=False)
degree = forms.CharField(max_length=40, required=False)
school = forms.CharField(max_length=40, required=False)
edu_start_date = forms.DateField(required=False, input_formats=settings.DATE_INPUT_FORMATS)
edu_end_date = forms.DateField(required=False, input_formats=settings.DATE_INPUT_FORMATS)
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
super(ProfileSettingsForm, self).__init__(*args, **kwargs)
self.fields['job_title'].initial = self.instance.experience.job_title
self.fields['company'].initial = self.instance.experience.company
self.fields['description'].initial = self.instance.experience.description
self.fields['exp_start_date'].initial = self.instance.experience.exp_start_date
self.fields['exp_end_date'].initial = self.instance.experience.exp_end_date
self.fields['degree'].initial = self.instance.education.degree
self.fields['school'].initial = self.instance.education.school
self.fields['edu_start_date'].initial = self.instance.education.edu_start_date
self.fields['edu_end_date'].initial = self.instance.education.edu_end_date
def save(self, commit=True):
model = super(ProfileSettingsForm, self).save(commit=False)
jt = self.cleaned_data['job_title']
co = self.cleaned_data['company']
desc = self.cleaned_data['description']
esd = self.cleaned_data['exp_start_date']
eed = self.cleaned_data['exp_end_date']
degree = self.cleaned_data['degree']
school = self.cleaned_data['school']
edusd = self.cleaned_data['edu_start_date']
edued = self.cleaned_data['edu_end_date']
if model.experience:
model.experience.job_title = jt
model.experience.company = co
model.experience.description = desc
model.experience.exp_start_date = esd
model.experience.exp_end_date = eed
model.experience.save()
else:
model.experience = Work_Experience.objects.create(job_title=jt,
company=co,
description=desc,
exp_start_date=esd,
exp_end_date=eed)
if model.education:
model.education.degree = degree
model.education.school = school
model.education.edu_start_date = edusd
model.education.edu_end_date = edued
model.education.save()
else:
model.education = Education.objects.create(degree=degree,
school=school,
edu_start_date=edusd,
edu_end_date=edued)
if commit:
model.save()
return model
视图.py
class ProfileSettingsView(UpdateView):
model = Profile
form_class = ProfileSettingsForm
pk_url_kwarg = 'pk'
context_object_name = 'object'
template_name = 'profile_settings.html'
def get_success_url(self):
return reverse_lazy('users:profile_settings', args = (self.object.id,))
更新
如果我删除表单中的 init() 方法,错误就会解决。但是一旦我保存它,我就不会从表单字段中的数据库中获取值。如何重写 init() 方法?
def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
super(ProfileSettingsForm, self).__init__(*args, **kwargs)
self.fields['job_title'].initial = self.instance.experience.job_title
self.fields['company'].initial = self.instance.experience.company
self.fields['description'].initial = self.instance.experience.description
self.fields['exp_start_date'].initial = self.instance.experience.exp_start_date
self.fields['exp_end_date'].initial = self.instance.experience.exp_end_date
self.fields['degree'].initial = self.instance.education.degree
self.fields['school'].initial = self.instance.education.school
self.fields['edu_start_date'].initial = self.instance.education.edu_start_date
self.fields['edu_end_date'].initial = self.instance.education.edu_end_date
解决方案
为什么会出错?
在行中:
self.fields['job_title'].initial = self.instance.experience.job_title
您正在处理一个Profile
没有相关的实例experience
。
如何定义 post_save 信号,以便在创建配置文件时创建经验和教育?
如果您希望每次创建 aProfile
它都会填充 amexperience
并且education
您应该有一个信号,例如:
def create_profile(sender, instance, created, **kwargs):
if created:
experience = Work_Experience.objects.create(profile=instance)
education = Education.objects.create(profile=instance)
post_save.connect(create_profile, sender=Profile)
为什么调用表单post_save
时没有触发信号?save()
model = super(ProfileSettingsForm, self).save(commit=False)
根据文档:
这个 save() 方法接受一个可选的 commit 关键字参数,它接受 True 或 False。如果您使用 commit=False 调用 save(),那么它将返回一个尚未保存到数据库的对象。在这种情况下,您可以在生成的模型实例上调用 save() 。如果您想在保存对象之前对其进行自定义处理,或者如果您想使用专门的模型保存选项之一,这将非常有用。提交默认为真。
所以当你这样做的时候:
model.experience.job_title = jt
您的post_save
信号尚未被触发,因此model.experience
仍然存在None
错误:
“NoneType”对象没有属性 job_title。
推荐阅读
- java - 处理多线程拆分器/聚合器编排内部的异常以转到聚合器而不是 MessagingGatewaySupport 的 errorChannel
- python - 在 Dataframes 之间动态执行 AND OR NOT 操作的最佳方法?
- python - Pycharm 热键/设置将 *args 调用更改为 **kwargs 调用
- tensorflow - TfLite 转换器 TOCO 失败
- sap-ase - 相同的查询在 Sybase 10 和 Sybase 15 中显示不同的输出
- python - 如何检查预期数据是否通过 post 或 put 请求发送?
- python-3.x - pymongo 将 mongoDB 日期转换为 python 日期时间
- node.js - Angular中美人鱼集成的问题
- python - 无法安装烧瓶询问:来自密码学模块的错误
- c# - 在 WPF 中的单击事件后将一个按钮拆分为两个单独的按钮