首页 > 解决方案 > 在这种情况下,为什么 UserChangeForm 模型会创建一个对象而不是更新它?

问题描述

我现在正在使用 UserChangeForm 来更新用户表单,当我尝试通过请求发送帖子时,该函数确实有效,但不会更改用户对象,而是像 create 方法一样保存对象。那么,此时我怎么能改变表单对象呢?

视图.py

# Edit Your account
@login_required
def edit_profile(request, user_slug=None):
    template_name = 'account/edit_profile.html'
    if request.method == "POST":
        request_user = request.user.userprofile
        user_profile = UserProfile.objects.get(slug=user_slug)
        form = EditForm(request.POST)
        if form.is_valid():
            form.instance.slug = user_slug
            form.save()
            return redirect('account:view_profile', form.instance.slug)
        return render(request, template_name, {'form': form})
    else:
        form = EditForm()
        user_profile = UserProfile.objects.get(slug=user_slug)
        return render(request, template_name, {'form': form})

网址.py

urlpatterns = [
    path('view-profile/<slug:user_slug>/', views.view_profile, name='view_profile'),
    # /account/edit-profile/
    path('edit-profile/<slug:user_slug>/', views.edit_profile, name='edit_profile'),
]

edit_form.html

{% extends 'base.html' %}
{% block title %} Edit Profile {% endblock %}

{% block body %}

    <div class="edit-form">
        <div class="container">
            <div class="my-form">
                <form method="post">
                    {% csrf_token %}
                    {% for field in form %}
                    <div class="form-group">
                        <label for="exampleInputEmail1">{{ field.label_tag }}</label>
                        <p>{{ field }}</p>
                    </div>
                    {% endfor %}
                <button type="submit" class="btn btn-primary btn-lg">Change Password</button>
                </form>
            </div>
        </div>
    </div>

    {% include 'base_footer.html' %}

{% endblock %}

表格.py

# Edit your data except password
class EditForm(UserChangeForm):
    password = None

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

    def edit(self, fields):
        user = super(EditForm, self).save(commit=False)

        if user.commit:
            user.save()
        return user

标签: pythondjangodjango-modelsdjango-forms

解决方案


您不需要在 ModelForm 上提供编辑功能,我建议使用基于类的通用视图,因为它易于使用和扩展。这是我的建议:

表格.py

class UpdateUserForm(ModelForm):
    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'email']

#views.py

from django.views.generic import View
from .forms import UpdateUserForm
from django.contrib import messages
#import your forms and functions including UpdateUserForm

class UserView(View):
    def get(self, *args, **kwargs):
        form = UpdateUserForm(instance=self.request.user)
        context = {'form':form}
        return render(self.request, template, context)

    def post(self, *args, **kwargs):
        form = UpdateUserForm(self.request.POST or None, instance=self.request.user)
        if form.is_valid():
            form.save()
            messages.success(self.request, 'Info updated')
            return redirect('user-profile')
        context = {'form':form}
        messages.error(self.request, 'Please, check the form for errors')
        return render(self.request, template, context)



#function based view
def update_user(request):
    form = UpdateUserForm(instance=request.user)
    if request.method == 'POST':
        form = UpdateUserForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            return render(...)
    return render(request, template, {'form':form}

这就是我为用户信息更新创建视图的方式,它就像一个魅力

模板文件

{% extends 'base.html' %}
{% block title %} Edit Profile {% endblock %}

{% block body %}

<div class="edit-form">
    <div class="container">
        <div class="my-form">
            <form method="post">
                {% csrf_token %}
                {% for field in form %}

                            <div
                                class="input-group no-border form-control-lg {% if field.errors %} has-danger {% endif %} ">
                                <span class="input-group-prepend">
                                    <div class="input-group-text">
                                        <i class="now-ui-icons users_single-02"></i>
                                    </div>
                                </span>
                                {% render_field field class="form-control" %}
                            </div>

                            {% if field.errors %}
                            {% for error in field.errors %}
                            <div class="text-left text-danger font-weight-bolder">
                                <p>{{ error|escape}}</p>
                            </div>
                            <script>
                            $('.form-control').addClass('form-control-danger')
                            </script>
                            {% endfor %}
                            {% endif %}

                            {% endfor %}
            <button type="submit" class="btn btn-primary btn-lg">Change Password</button>
            </form>
        </div>
    </div>
</div>

{% include 'base_footer.html' %}

{% endblock %}

如果你使用 Bootstrap,你可以使用 Javascript 添加样式

{% block page_script %}
<script>
var $list = $("form :input[type='text']");
$list.each(function () {
    $(this).addClass("form-control");
});
var $select = $("form select");
$select.each(function () {
    $(this).addClass("custom-select w-90");
});
var $select = $("form textarea");
$select.each(function () {
    $(this).addClass("form-control");
});
var $list = $("form :input[type='number']");
$list.each(function () {
    $(this).addClass("form-control");
});
{% endblock %}

推荐阅读