首页 > 解决方案 > 为外键字段创建 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 

标签: pythondjangopython-3.xdjango-models

解决方案


为什么会出错?

在行中:

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。


推荐阅读