I am trying to create signup form adding email field in django from base class UserCreationForm. The code goes as
form.py
class ussignup(UserCreationForm):
email=forms.EmailField(required=True)
first_name=forms.CharField(required=False)
last_name=forms.CharField(required=False)
class Meta:
model=User
fields=('username','password1','password2','first_name','last_name','email',)
#fields=('username','password','first_name','last_name','email')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email=self.cleaned_data["email"]
user.first_name=self.cleaned_data["first_name"]
user.last_name=self.cleaned_data["last_name"]
if commit:
user.save()
return user
view.py
def signup(request):
if request.method=='POST':
form=ussignup(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/rgsuc')
args={}
args.update(csrf(request))
args['form']=form
return render_to_response('register.html',args)
urls.py
url(r'^accounts/signup',signup),
Error
output shows the form however the password entered in the field is not saved in database. Thus shows no password when viewed from admin and thus unable to login.
ok I finally got it, I need to add
user.set_password(self.cleaned_data["password1"])
which I thought it will be saved by django itself however I have overriden the save function thus need to save it also
Or else you could have only changed this (i.e. your class name ussignup, instead of the base class UserCreationForm) in the method, and it would have worked.
def save(self, commit=True):
user = super(ussignup, self).save(commit=False)
user.email=self.cleaned_data["email"]
user.first_name=self.cleaned_data["first_name"]
user.last_name=self.cleaned_data["last_name"]
if commit:
user.save()
return user
Hope this will help.
Related
I'm new to Django and I've correctly created my first web app where I can register and login as an user. I'm using the standard from django.contrib.auth.models import User and UserCreationFormto manage this thing.
Now, I would like to create a new table in the database to add new fields to the user. I'm already using the standard one such as email, first name, second name, email, username, etc but I would like to extend it by adding the possibility to store the latest time the email has been changed and other info. All those info are not added via the form but are computed by the backend (for instance, every time I want to edit my email on my profile, the relative field on my new table, linked to my profile, change value)
To do that I have added on my models.py file the current code
from django.db import models
from django.contrib.auth.models import User
class UserAddInformation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_time_email_change = models.TimeField('Last email changed', auto_now_add=True, blank=True)
def __str__(self):
return self.user.username
And on my admin.py
from django.contrib import admin
from .models import UserAddInformation
admin.site.register(UserAddInformation)
The form to edit the email and the view can be found below
forms.py
class EditUserForm(UserChangeForm):
password = None
email = forms.EmailField(widget=forms.EmailInput(attrs={
'class': 'form-control'
}))
class Meta:
model = User
# select the fields that you want to display
fields = ('email',)
views.py
#authenticated_user
def account_user(request):
if request.method == "POST":
form = EditUserForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
user_info_obj = UserAddInformation.objects.create(user=request.user,
last_time_email_change=datetime.now())
user_info_obj.save()
messages.success(request, "Edit Succesfully")
else:
pass
else:
form = EditUserForm()
return render(request, 'authenticate/account.html', {
'form_edit': form,
})
The issue is that, once I'm going to update the email via the form, I got an error UNIQUE constraint failed: members_useraddinformation.user_id
Using ForeignKey make it works but it create a new row in the table, with the same when I just want to update the first one
The edit process for the email works tho
What am I doing wrong?
It turned out that auto_now_add=True inherit editable=False generating the error. So changing my models.py with
class UserAddInformation(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_time_email_change = models.TimeField('Last email changed')
def save(self, *args, **kwargs):
self.last_time_email_change = timezone.now()
return super(UserAddInformation, self).save(*args, **kwargs)
def __str__(self):
return self.user.username
and checking with
user_info_obj = UserAddInformation.objects.get_or_create(user=request.user)
user_info_obj[0].save()
inside def account_user(request): worked
I'm not sure it's the best solution for my issue tho
I am starting with Django, and I have a question about the connection between a post and the user who created it. For now, I managed to create the link, however, whenever I create a new post, the user id is always the default one, thus one. I want to make it in a way that the user id is the id of the person creating the post, and for some reason, it never works. The other option I tried is to put "user" into the form but the problem is that then the user can choose which user he is, which is risky. So is there any way to make it automatic? That when the post is created, the right user id is directly connected to it? Thank you for any help!!
model.py
"""
class Post(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE, default=1)
image = models.ImageField(default="man.jpg")
titre = models.CharField(max_length=50)
slug = models.SlugField(max_length=100)
date_publication = models.DateTimeField(auto_now_add=True)
"""
view.py
"""
#login_required
def post_create(request):
if request.method == "POST":
post_form = PostForm(request.POST)
if post_form.is_valid():
post_form.save()
messages.success(request, 'Your post was successfully created!')
return redirect('seed:view_seed')
else:
messages.error(request, 'Please correct the error below.')
else:
post_form = PostForm(request.POST)
return render(request, "post/create.html", context={"post_form": post_form})
"""
forms.py
"""
class PostForm(ModelForm):
class Meta:
model = Post
fields = ["user", "image", "titre", "slug"]
"""
You remove the user field from the fields in the form:
class PostForm(ModelForm):
class Meta:
model = Post
# no user ↓
fields = ['image', 'titre', 'slug']
and in the view you add the logged in user to the instance wrapped in the form:
#login_required
def post_create(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
# add user to the instance ↓
post_form.instance.user = request.user
post_form.save()
messages.success(request, 'Your post was successfully created!')
return redirect('seed:view_seed')
else:
messages.error(request, 'Please correct the error below.')
else:
post_form = PostForm()
return render(request, "post/create.html", context={"post_form": post_form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I wrote two views as the class in Django in order to do the Registration and Login for my website. But the problem is that the user objects get created successfully. But when I try to authenticate later getting the warning message showing that user with that username already exists in Django
The two views are given below
class RegistrationView(View):
form_class=RegistrationForm
template_name='eapp/user_registration_form.html'
def get(self,request):
form=self.form_class(None)
return render(request,self.template_name,{'form':form})
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
user=form.save(commit=False)
#cleaned (normalized) data
username =form.cleaned_data['username']
password =form.cleaned_data['password']
email=form.cleaned_data['email']
user.set_password(password)
user.save()
return render(request,self.template_name,{'form':form,})
class LoginView(View):
form_class=LoginForm
template_name='eapp/user_login_form.html'
def get(self,request):
form=self.form_class(None)
return render(request,self.template_name,{'form':form})
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
#cleaned (normalized) data
username =form.cleaned_data['username']
password =form.cleaned_data['password']
#authenticatin
user=authenticate(username=username,password=password)
if user is not None:
if user.is_active:
login(request,user)
return render(request,'eapp/index.html',{})
return render(request,self.template_name,{'form':form,})
here is my forms.py'
from django.contrib.auth.models import User
from django import forms
class RegistrationForm(forms.ModelForm):
password=forms.CharField(widget=forms.PasswordInput)
class Meta:
model=User
fields=['username','email','password']
class LoginForm(forms.ModelForm):
password=forms.CharField(widget=forms.PasswordInput)
class Meta:
model=User
fields=['username','password'
]
How can I solve this? ThankYou
Change your LoginForm for a Form without model:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(label = 'Nombre de usuario')
password = forms.CharField(label = 'ContraseƱa', widget = forms.PasswordInput)
This way your form will validate that the fields are entered and will not take validations from the User model
Ok so I actually solved this one by accident and would simply like to understand what happened.
I have my own user registration form BaseCreationForm which extends a ModelForm and uses a UserProfile as its model. All the validation methods were working fine, but the save method was giving me grief. Whenever I tried to create a user (the profile is created in the view, I may refactor this), Django would tell me that "BaseCreationForm object has no attribute cleaned data".
BUT, when out of frustration and running out of ideas I added a simple "print self" statement before creating the user in the save() method, the problem disappeared and users are being created normally. Below are a couple of clean() methods that work, the save() method and a snippet from the view that calls the clean() and save() method.
clean() methods working normally
#example clean methods, both work beautifully
def clean_email(self):
email = self.cleaned_data["email"]
if not email:
raise forms.ValidationError(self.error_messages['no_email'])
try:
User.objects.get(email=email)
except User.DoesNotExist:
return email
raise forms.ValidationError(self.error_messages['duplicate_email'])
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'])
return password2
save() method:
#save method requiring wizardry
def save(self, commit=True):
#This line makes it work. When commented, the error appears
print self
###
user = User.objects.create_user(
username=self.cleaned_data.get("username"),
first_name=self.cleaned_data["first_name"],
last_name=self.cleaned_data["last_name"],
email=self.cleaned_data["email"],
)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
And the view (some stuff left out):
class RegistrationView(FormView):
template_name = 'register.html'
form_class = BaseCreationForm
model = UserProfile
success_url = '/account/login/'
def form_valid(self, form):
form = BaseCreationForm(self.request.POST,
self.request.FILES)
user = form.save()
profile = user.get_profile()
profile.user_type = form.cleaned_data['user_type']
profile.title = form.cleaned_data['title']
profile.company_name = form.cleaned_data['company_name']
.
.
.
profile.save()
return super(RegistrationView, self).form_valid(form)
You shouldn't be re-instantiating the form inside the form_valid method. That's called when the form is already valid, and indeed the form is passed into the method. You should use that instead.
(Note that the actual error is because you haven't called form.is_valid() at all, but as I say above you shouldn't, because the view is already doing it.)
I ran today into a special situation. Previously I had the following in my view.py
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password2'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('/register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {'form':form})
return render_to_response('registration/register.html', variables)
It was pretty straight forward retrieving the username, email and password to create a new user after she has registered. But now I have refactored it to use a hash code as the username and utilize the email alone to register and login.
The shortened RegistrationForm looks like this:
class RegistrationForm(forms.ModelForm):
email = forms.EmailField(label=_("Email"))
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput))
class Meta:
model = User
fields = ("email",)
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
email = self.cleaned_data['email']
user.username = md5(email).digest().encode('base64')[:-1]
if commit:
user.save()
return user
The new form doesn't have the username any longer, since it is calculated and not entered by the user any more. But how do I retrieve the username from the view ? The new code is not from me and I have it from a blog. Maybe the key is here in the Meta class? From the documentation I wasn't able to fully understood what he is trying to achieve with the Meta class here...
Many Thanks,
EDIT:
Ok I think I understand now how the subclassing should work. I tried to subclass the User class like this:
class cb_user_model_backend(ModelBackend):
def create_user(self, email=None, password=None):
"""
Creates and saves a User with the given email and password only.
"""
now = timezone.now()
username = md5(email).digest().encode('base64')[:-1]
email = UserManager.normalize_email(email)
user = self.model(username=username, email=email,
is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_joined=now)
user.set_password(password)
user.save(using=self._db)
return user
The problem I am facing now are two errors, self._db and self.model, were meant to be on the base user class. How do get to them from here?
Edit 2:
PyCharm complains that the two self._db and seld.model don't exit on current cb_user_model_backend.
Note the View is refactored to take two parameters:
user = User.objects.create_user(
password=form.cleaned_data['password2'],
email=form.cleaned_data['email']
)
When running it stack trace is:
Exception Type: TypeError
Exception Value:
create_user() takes at least 2 arguments (3 given)
Try subclassing your save method in your models.py:
def save(self, *args, **kwargs):
if not self.id:
self.username = md5(self.email).digest().encode('base64')[:-1]
super(ModelName, self).save(*args, **kwargs)
After calling user.save(), user.username should yield the generated username in your views. Hope this helps.
EDIT:
If you want to call create_user(**kwargs), you could do the following in your views.py:
email = self.cleaned_data['email']
username = md5(email).digest().encode('base64')[:-1]
u = User.objects.create_user(username = username, email = email, password = password)