I have a UserProfile model which is linked OneToOne with Django User model. While adding a user through a form, I wanted to have one form for both of those. I found a snippet that does exactly that, and I didn't have any problem with it, until I wanted to validate the username. The form isn't throwing a ValidationError, like I would like it to, but returns an error page with ValueError: The User could not be created because the data didn't validate..
From what I understand (which obviously could be wrong), the current setup doesn't handle ValidationErrors from the nested form.
Is there any way to add that functionality? If not, how should I tackle the issue of having one form handle to models?
Code:
class CmUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(),
required=False,
help_text=_("Leave empty if you don't want "
"to change it"))
def clean_password(self):
data = self.cleaned_data['password']
if data.strip():
return make_password(data)
else:
# If password field is empty, then don't change it
return self.instance.password
def clean_username(self):
username = self.cleaned_data['username']
if get_user_model().objects.filter(username=username).exists():
raise forms.ValidationError(_('This username is already in use.'))
return username
class Meta:
model = get_user_model()
fields = ('first_name', 'last_name', 'email', 'username', 'password', 'is_staff', 'is_active')
class CmUserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
# Take User if updating, None if creating
try:
self.user = kwargs['instance'].user
except AttributeError:
self.user = None
user_kwargs = kwargs.copy()
user_kwargs['instance'] = self.user
self.uf = CmUserForm(*args, **user_kwargs)
super(CmUserProfileForm, self).__init__(*args, **kwargs)
self.fields.update(self.uf.fields)
self.initial.update(self.uf.initial)
class Meta:
model = UserProfile
exclude = ['user']
def save(self, *args, **kwargs):
# Save User and pass it to UserProfile
user = self.uf.save(*args, **kwargs)
self.instance.user = user
return super().save(*args, **kwargs)
i implemented the same today. I learnt this from the this website tango with django. http://www.tangowithdjango.com/book/chapters/login.html. Also i provided my code how i achieved this. Inbuilt user model itself checks if the username already exists or not. hope this is helpful.
class Sam(models.Model):
user = model.OneToOneField(User)
#custom fields apart from the inbuilt User model
region = models.CharField(max_length=10)
designation = models.CharField(max_length=10)
#forms.py form models. Created SamProfileform to capture the custom fields which are specific to One's Profile and SamForm to capture the password and then hash later in the view.
#Please note that i didnt add any username check here. The inbuilt User does it for us. I verified it.
class SamForm(forms.ModelForm):
#form model to capture inbuilt fields of "User" model
password = forms.CharField(widget=PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password', 'firstname', 'lastname')
class SamProfileForm(forms.ModelForm):
#form model to built the custom fields in my case region and designation
class Meta:
model = Sam
fields = ('desgination', 'mgr')
def register(request):
registered = False
if request.method == 'POST':
user_form = SamForm(data=request.POST)
profile_form = SamProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
registered = True
else:
print user_form.errors, profile_form.errors
else:
user_form = SamForm()
profile_form = SamProfileForm()
template = loader.get_template('sam/register.html')
context = RequestContext(request, {
'user_form' : user_form, 'profile_form' : profile_form, 'registered' : registered,
})
return HttpResponse(template.render(context))
Related
I have a register user form which is doing all the validation as expected. However, it is not saving. I am not able to figure out the reason. How do I debug it ? Any help ? I am a newbie to forms and formviews any good document with example would really help me.
class RegisterForm(forms.ModelForm):
phone_number = forms.IntegerField(required=True)
password1 = forms.CharField(widget=forms.PasswordInput())
password2 = forms.CharField(widget=forms.PasswordInput())
country_code = forms.IntegerField()
#schools = school.objects.all()
#school_name = forms.ModelChoiceField(queryset=school.objects.distinct())
MIN_LENGTH = 4
class Meta:
model = User
fields = ['username','country_code','phone_number', 'password1', 'password2',
'full_name' ]
def clean_phone_number(self):
phone_number = self.data.get('phone_number')
print(phone_number)
if User.objects.filter(phone_number=phone_number).exists():
raise forms.ValidationError(
_("Another user with this phone number already exists"))
if len(phone_number) == 10 and phone_number.isdigit():
pass
else:
raise forms.ValidationError(
_("Invalid Phone Number"))
return phone_number
def save(self, *args, **kwargs):
print("saving")
user = super(RegisterForm, self).save(*args, **kwargs)
user.set_password(self.cleaned_data['password1'])
print('Saving user with country_code', user.country_code)
user.save()
return user
Views.py
class RegisterView(SuccessMessageMixin, FormView):
template_name = 'register-2.html'
form_class = RegisterForm
success_message = "One-Time password sent to your registered mobile number.\
The verification code is valid for 10 minutes."
def form_valid(self, form):
full_name=self.request.POST["full_name"]
user = form.save()
print(user.id)
username = self.request.POST['username']
password = self.request.POST['password1']
user = authenticate(username=username, password=password)
kwargs = {'user': user}
self.request.method = 'POST'
print("User created")
The print in clean_phone_number works however, save does not work
I had issue in the my form. One of the field was disabled and the value was not captured because of that.
However to identify that I used
def form_invalid(self,form):
# Add action to invalid form phase
messages.error(self.request, form.errors)
return self.render_to_response(self.get_context_data(form=form))
I am using Django built-in authentication views and form to create a registration/login system, and I'm using the UserCreationForm to register a user but only the username is required. I only want to make other User fields required as well. What is the simplest way to do that without creating a new user model?
Here are my forms:
# Create user registration form class.
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = UserCreationForm.Meta.fields + ('first_name', 'last_name', 'email',)
And here are my views:
def register(request):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse('index'))
elif request.method == 'GET':
form = CustomUserCreationForm()
elif request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
form.save()
context = {
'user': request.user,
}
return HttpResponseRedirect(reverse('index'), context)
else:
return HttpResponseRedirect(reverse('register'))
else:
return HttpResponse("Project 3: TODO")
context = {
'form': form,
}
return render(request, 'registration/signup.html', context)
You can override the fields for first and last name on the form to make them required. Note, this won't change the fact that the database table still allows null values for those fields
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(required=True, max_length=150)
last_name = forms.CharField(required=True, max_length=150)
class Meta:
model = User
fields = UserCreationForm.Meta.fields + ('first_name', 'last_name', 'email',)
I am developing a django website where seller can open their accounts and update their profiles,so while while creating seller account I want to create a profile objects,my code of user registration form is given below,
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(required=True)
date_of_birth = forms.DateField(required=True,
input_formats=settings.DATE_INPUT_FORMATS)
class Meta:
model = User
fields = ['username', 'email', 'date_of_birth', 'password1',
'password2']
def save(self, commit=True):
date_of_birth = self.cleaned_data.pop('date_of_birth', None)
user = super(UserRegisterForm, self).save(commit)
seller = Seller.objects.create(name=user.username,
date_of_birth=date_of_birth, created_by=user)
profile = Profile.objects.create(seller=seller)
return user
my code for become_seller in views.py is,
def become_seller(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('seller_dashboard')
else:
form = UserRegisterForm()
return render(request, 'become_seller.html',{'form':form})
all of this is working fine,but when I go for edit profile,my code for edit in views.py is,
#login_required
def edit(request):
if request.method == 'POST':
profile_form =
ProfileEditForm(instance=request.user.seller.profile,
data=request.POST, files=request.FILES)
if profile_form.is_valid():
profile_form.save()
else:
profile_form =
ProfileEditForm(instance=request.user.seller.profile)
return render(request, 'profile_edit.html',
{'profile_form':profile_form})
so,while working for this I found the following error message
AttributeError at /seller/edit/ 'Seller' object has no attribute 'profile'
can anyone help me to sort out this issue please
try register also ListingAdmin like admin.site.register(Listing, ListingAdmin) instead of trying to register only model class
ListingAdmin is not registered in admin.site.register()
The issue is solved by using related_name = profile
I am using Django's built in authentication to manage users on a social media website. I am using a one-to-one relationship to attach a profile to each user. I can update all the parts of the profile I have attached using an UpdateView. However I don't know how to do that with Django's built in User. So I created a form that uses the _meta class. I have gotten to the point where my form will add a new user instead of update the current one. I was hoping one of you could help me fix my code. Thanks in advance for any help you can offer
views.py
class PrivProfileUpdate(View):
form_class = UserUpdateForm
template_name = 'user/user_form.html'
#display a blank form
def get(self, request, pk):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
#proces form data
def post(self, request, pk):
form = self.form_class(request.POST)
user = User.objects.get(pk=pk)
if form.is_valid():
user = form.save(commit=True)
print("we are trying to save")
#cleaned (normalized) data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
user.set_password(password) #this is the only way to change a password because of hashing
user.save()
return render(request, self.template_name,{'form': form})
forms.py
class UserUpdateForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'email', 'password', 'first_name', 'last_name']
SOLUTION:
in views.py
class PrivProfileUpdate(UpdateView):
model = User
form_class = UserUpdateForm
template_name = 'user/user_form.html'
def form_valid(self, form):
user = form.save(commit=True)
password = form.cleaned_data['password']
user.set_password(password)
user.save()
return redirect('user:index')
There's nothing special about the User class here. Just as with any other model, to update an existing instance you pass it as the instance argument to the form.
However, you do not actually need to do this at all yourself. You should be using an UpdateView, which does this for you; then you do not need to define get and post. The only method you need to define here is form_valid, to set the password:
class PrivProfileUpdate(UpdateView):
form_class = UserUpdateForm
template_name = 'user/user_form.html'
def form_valid(self, form):
user = form.save(commit=True)
password = form.cleaned_data['password']
user.set_password(password)
user.save()
return HttpResponseRedirect(self.get_success_url())
I'm new with Django and Python... I'm trying to do my own registration form for add some additional fields (Following the docs about Profiles)... All fine when I test, but after save, the additional field don't save, without error, just don't save, only the User is created... but If I write manually some values on create_profile function, it's saved correct.. How I can pass fields from my UserCreateForms to create_profile routine?
Sorry for my english, and thanks for your help, I'm involved in a little project for learn and I'm stopped for this detail.. :S
Models
class UserProfile(models.Model):
user = models.OneToOneField(User)
cedula_de_identidad = models.CharField(max_length=9)
def create_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance, cedula_de_identidad='If I write here it's saved correctly')
post_save.connect(create_profile, sender=User)
Forms
class UserCreateForm(UserCreationForm):
email = forms.EmailField(required=True)
cedula_de_identidad = forms.CharField(required=True)
class Meta:
model = User
fields = ("email", "username", "password1", "password2")
def clean_username(self):
username = self.cleaned_data['username']
# if not re.search(r'^\w+$', username):
# raise forms.ValidationError('Username can contain only alphanumeric characters')
try:
User.objects.get(username=username)
except ObjectDoesNotExist:
return username
raise forms.ValidationError('Username is already taken')
def save(self, *args, **kwargs):
user = super(UserCreateForm, self).save(*args, **kwargs)
profile = UserProfile()
profile.user = user
profile.cedula_de_identidad = self.cleaned_data['cedula_de_identidad']
profile.save
return profile
Views
def nuevo_usuario(request):
if request.method == 'POST':
formulario = UserCreateForm(request.POST)
if formulario.is_valid():
formulario.save()
return HttpResponseRedirect('/')
else:
formulario = UserCreateForm()
return render_to_response('nuevousuario.html', {'formulario': formulario}, context_instance=RequestContext(request))
I'm using Python 2.7 and Django 1.4.. Regards,