【问题标题】:Automatically updating a model field when it is created创建时自动更新模型字段
【发布时间】:2021-04-02 07:42:23
【问题描述】:

我想在创建模型字段时自动更新它。所以这就是我的情况。我有一个自定义用户模型,我的客户可以使用它来登录。登录后,他们将转到包含表单链接的帐户/个人资料页面。目前,当用户提交表单时,它会创建一个 LevelTest 模型的实例(这是我网站运行所需要的)。这是表单的视图类:

class LevelTestView(generic.CreateView):
    template_name = "leads/leveltest.html"
    form_class = LevelTestModelForm

    def get_success_url(self):
        return reverse("profile-page")

这里是 LevelTestModelForm:

class LevelTestModelForm(forms.ModelForm):
    class Meta:
        model = LevelTest
        fields = (
            'first_name',
            'last_name',
            'age',
            'username',
        )

我要自动填写的是用户名字段。事实上,我希望当用户输入时它甚至不会出现在表单本身。username 是用户模型中的一个字段,所以我只希望新的 LevelTest 的username 字段填充当前用户的用户名。因此,我使用了如下所示的 post_save 信号(不起作用):

def post_leveltest_created_signal(sender, instance, created, **kwargs):
    if created:
        instance.objects.update(
            username=instance.user.username,
            description='Add Description',
            phone_number=instance.user.cellphone,
            email=instance.user.username,
        )

    
post_save.connect(post_leveltest_created_signal, sender=LevelTest)

我希望你们能帮我调整一下 post_save 信号,这样当用户创建 LevelTest 实例时,LevelTest 的用户名字段(以及 phone_number 和电子邮件)都会填写用户模型的信息。非常感谢!

【问题讨论】:

    标签: python django django-views django-forms signals


    【解决方案1】:

    如果我理解你的正确,你不需要使用信号,你可以更容易地保存用户名:

    在您的 CreateView 中扩展 get_form_kwargs 方法,如下所示:

     class LevelTestView:(generic.CreateView)
         ...
         def get_form_kwargs(self):
             kwargs = super().get_form_kwargs()
             kwargs['user'] = self.request.user
             return kwargs
    

    在您的Form 中扩展__init__save 方法,如下所示:

    class LevelTestModelForm(forms.ModelForm):
        ...
        def __init__(self, user, *args, **kwargs):
            self.user = user
            super().__init__(*args, **kwargs)
        ...
        def save(self, commit=True):
            leveltest = super().save(commit=False)
            # I think it would be better if you saved only 'user' instance
            # like this - leveltest.user = self.user (of course if you have fk to user model)
            leveltest.username = self.user.username
            leveltest.phone_number=self.user.cellphone
            leveltest.email=self.user.username
            leveltest.save()
            return leveltest
    

    【讨论】:

    • 感谢您的评论。但是,当我提交表单时出现此错误:get_form_kwargs() 接受 1 个位置参数,但给出了 2 个
    • 你有没有像这样扩展 init 方法 - def __init__(self, user, *args, **kwargs):???
    • 我刚刚复制并粘贴了您的代码。但是,当我将 kwargs = super().get_form_kwargs(self) 更改为我发现的另一个代码:kwargs = super(LevelTestView, self).get_form_kwargs(**kwargs) 时,它以某种方式工作......
    • 我还添加了 **kwargs 作为 get_form_kwargs 的第二个参数。
    • 我不确定这是否可以...此外,手机字段被添加到 LevelTest 实例中,如下所示:('0192342342',)。我希望它可能只是 0192342342。有什么想法吗?
    【解决方案2】:

    我认为@KIN1991 的答案非常棒,但是您可以通过重写form_valid 方法来进一步最小化/优化代码。像这样:

    class LevelTestView:(generic.CreateView)
        ...
        def form_valid(self, form, *args, **kwargs):
           user = self.request.user
           form.instance.username = user.username
           form.instance.phone_number=user.cellphone,
           form.instance.email=user.username
           return super().form_valid(form, *args, **kwargs)
    

    【讨论】:

    • 在视图中保留逻辑不是一个好习惯,视图类必须尽可能的精简
    • 是的。真正简单的人。非常感谢!正是我想要的“简短易懂”的代码!
    • @KIN1991这取决于您要如何设计编码结构。你可以在这里查看我的首选做法:stackoverflow.com/a/57387971/2696165
    • 这只是很好的做法,对吗?那么,上面的代码没有任何功能问题吗?
    • @ruddra 是的,将逻辑保留在某个新层中,这是一种很好的做法,但在这种情况下,最好将逻辑保留在表单类中,因为这种逻辑与表单逻辑相关。除了 Django 的开发人员制作了 get_form_kwargs 方法,用于在此问题中描述的相同情况下使用。但这只是我的意见=))
    猜你喜欢
    • 2012-08-06
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多