django插入而不是更新

时间:2017-10-29 00:47:09

标签: django model

我已经阅读了很多与此问题相关的问题,但我还没有找到解决方案。在我的应用程序中,用户登录并可能更改HIS / HER配置文件中的某些字段。基本上,我需要的是更新用户的个人资料而不是创建一个新的个人资料。这是我的观点:

@login_required
def profile(request, user_id):

    try:
        user = User.objects.get(pk=user_id)
        profile = Profile.objects.get(pk=user_id)
        ProfileFormset = inlineformset_factory(
            User, Profile, fields=('nick_name', ), can_delete=False)
    except:
        return render_access_denied_message(request)

    if request.user.is_authenticated() and request.user.id == user.id:
        if request.method == 'POST':
            user_form = UserProfileForm(instance=user, data=request.POST)
            if user_form.is_valid():
                profile_formset = ProfileFormset(
                    request.POST, instance=profile)
                #assert False, profile_formset.is_valid()
                if profile_formset.is_valid():
                    #assert False, user_form  # at this point both form are valid
                    current_user = user_form.save()
                    #saves a new user with empty username
                    #assert False, current_user
                    profile_formset.user_id = user_id
                    profile_formset.save()
                    return confirmation_page(request, user_id)

            return render_access_denied_message(request)

        else:
            user_form = UserProfileForm(instance=user)
            profile_formset = ProfileFormset(instance=user)

        return render(request, 'users/profile.html', {
            'user_id': request.user.id,
            'form': user_form,
            'formset': profile_formset,
        })
    else:
        render_access_denied_message(request)

我的模特是:

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver


class Profile(models.Model):
    user = models.OneToOneField(
       User, related_name='user', on_delete=models.CASCADE, primary_key=True)
    nick_name = models.CharField(
       'Nick name', max_length=30, blank=True, default='')

def __str__(self):
    return self.user.username


def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        profile = Profile(user=user)
        profile.nick_name = ''
        profile.save()


post_save.connect(create_profile, sender=User)

我的users.forms.py是:

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

    def __init__(self, *args, **kwargs):
       self.instance = kwargs.pop('instance')
       super(UserProfileForm, self).__init__(*args, **kwargs)
       self.fields['first_name'].required = True
       self.fields['last_name'].required = True
       self.fields['email'].required = True

    def validate_non_numeric(self, str_exp):
        pattern = re.compile(r"([a-zA-Z]+)")
        if not pattern.match(str_exp):
            raise ValidationError('Field is incorrect')
        return str_exp

    def clean_first_name(self):
        return self.validate_non_numeric(self.cleaned_data['first_name'])

    def clean_last_name(self):
        return self.validate_non_numeric(self.cleaned_data['last_name'])

    def clean_email(self):
        value = self.cleaned_data['email']
        pattern = re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)")
        if not pattern.match(value):
            raise ValidationError('Email format is incorrect')
        return value


class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['nick_name']

    def clean_nick_name(self):
        value = self.cleaned_data['email']
        pattern = re.compile(r"(^[a-zA-Z]+[a-zA-Z0-9-]+$)")
        if not pattern.match(value):
            raise ValidationError('Email format is incorrect')
        return value

- UPDATE -

我必须对view.py代码进行一些更改,感谢@VladT我已经以正确的方式完成了它。这是我的最终解决方案:

class ProfileUpdateView(UpdateView):
    template_name = 'users/profile.html'
    model = Profile
    form_class = UserProfileForm
    second_form_class = ProfileForm

    def form_valid(self, form, form2):
        user = self.get_object().user
        if form.is_valid() and form2.is_valid():
            form.save()
        return super(ProfileUpdateView, self).form_valid(form2)

    def get(self, request, *args, **kwargs):
        pk = self.kwargs.get('pk', None)
        self.request = request
        if self.request.user.is_authenticated(
        ) and self.request.user.id == int(kwargs['pk']):
            super(ProfileUpdateView, self).get(request, *args, **kwargs)
            user = User.objects.get(pk=pk)
            prfl = Profile.objects.get(pk=pk)
            form = self.form_class(instance=user)
            form2 = self.second_form_class(instance=prfl)
            return self.render_to_response(
                self.get_context_data(
                    object=self.object, form=form, form2=form2))

        return render_access_denied_message(request)

    def post(self, request, *args, **kwargs):
        pk = self.kwargs.get('pk', None)
        if pk is not None:
            user = User.objects.get(pk=pk)
            prfl = Profile.objects.get(pk=pk)
            user_form = self.form_class(instance=user, data=request.POST)
            profile_form = self.second_form_class(
                instance=prfl, data=request.POST)
            self.form_valid(user_form, profile_form)
            return confirmation_page(request, pk)

        else:
            render_access_denied_message(request)

    def get_success_url(self):
        return '/'

1 个答案:

答案 0 :(得分:0)

如果不需要formset,我建议将两个表单合并为一个:

# forms.py

class ProfileForm(forms.ModelForm):
    first_name = forms.CharField(max_length=30, label='First name')
    last_name = forms.CharField(max_length=30, label='Last name')
    email = forms.EmailField()

    class Meta:
        model = Profile
        fields = ['first_name', 'last_name', 'email', 'nick_name']

    def validate_non_numeric(self, str_exp):
        pattern = re.compile(r"([a-zA-Z]+)")
        if not pattern.match(str_exp):
            raise ValidationError('Field is incorrect')
        return str_exp

    def clean_first_name(self):
        return self.validate_non_numeric(self.cleaned_data['first_name'])

    def clean_last_name(self):
        return self.validate_non_numeric(self.cleaned_data['last_name'])

    def clean_nick_name(self):
        ...

并使用基于类的通用视图:

# views.py

class ProfileUpdate(UpdateView):
    model = Profile
    form_class = ProfileForm

    def form_valid(self, form):
        user = self.get_object().user
        user.first_name = form.cleaned_data['first_name']
        user.last_name = form.cleaned_data['last_name']
        user.email = form.cleaned_data['email']
        user.save()  # saves user object
        return super(ProfileUpdate, self).form_valid(form)  # saves profile

    def get_initial(self):
        initial = super(ProfileUpdate, self).get_initial()
        # populate form with User data
        user = self.get_object().user
        initial.update({
            'first_name': user.first_name,
            'last_name': user.last_name,
            'email': user.email,
        })
        return initial

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        if not kwargs['user_id'] == self.request.user.id:
            raise PermissionDenied
        return super(ProfileUpdate, self).dispatch(request, *args, **kwargs)