我已经阅读了很多与此问题相关的问题,但我还没有找到解决方案。在我的应用程序中,用户登录并可能更改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 '/'
答案 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)