python - 为外键字段创建 post_save 信号

标签 python django python-3.x django-models

我有一个个人资料模型,其中包含作为外国关键领域的经验和教育。 当我访问个人资料模板时,它会抛出异常。

enter image description here

我尝试过 post_save,

def create_education(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(education=instance)

    post_save.connect(create_education, sender=CustomUser)

它抛出这个错误,

enter image description here

如何定义 post_save 信号,以便在创建个人资料时创建经验和教育?

注意:我仔细检查了错误是因为外部字段为空,即当我在 django admin 中添加经验和教育字段时没有错误。

models.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)

forms.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

Views.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实例。

如何定义 post_save 信号,以便在创建个人资料时创建经验和教育?

如果您希望每次创建个人资料时都会填充经验教育,您应该有一个类似以下的信号:

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)

为什么调用表单的save()时没有触发post_save信号?

model = super(ProfileSettingsForm, self).save(commit=False)

根据文档:

This save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasn’t yet been saved to the database. In this case, it’s up to you to call save() on the resulting model instance. This is useful if you want to do custom processing on the object before saving it, or if you want to use one of the specialized model saving options. commit is True by default.

所以当你这样做时:

model.experience.job_title = jt

您的 post_save 信号尚未触发,因此 model.experience 仍为 None,因此出现错误:

'NoneType' object has no attribute job_title.

关于python - 为外键字段创建 post_save 信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54599050/

相关文章:

python - 如何减少Windows中的CPU使用率?

Python:发生外部异常时如何正确继续while循环

django - 在wagtail中索引自定义Django模型字段

python - 根据数据框中的另一个单元格值更改单元格值

python - 将字符串转换为二维 numpy 数组中的 float

python - 如何在 Python 中实现一个高效的无限质数生成器?

python - Python中的一对一继承

python - 调试与 EC2、Ubuntu 和 Django 断开的连接

Django 模型实用程序 : Use InheritanceManager with custom querysets

Django 数据库创建或更新错误