I have an app with 2 user levels; Superuser, and Staff. Superuser will login to this app and create a new user and assign the user either Superuser or Staff permissions, but they are not logging in through the default Django admin, they will be logging into a custom admin. How do I display the permission checkboxes in my form and how do I save them for that new user being created? Is it merely just a normal checkbox or is there something I need to override to be able to accomplish this?
Here is my CreateUserForm as it is now.
class CreateUserForm(forms.Form):
username = forms.EmailField(max_length=50)
email = forms.EmailField()
first_name = forms.CharField(max_length=150)
last_name = forms.CharField(max_length=150)
password1 = forms.CharField(max_length=30, widget=forms.PasswordInput(render_value=False), label='Password')
password2 = forms.CharField(max_length=30, widget=forms.PasswordInput(render_value=False), label='Password Confirmation')
address_1 = forms.CharField(max_length=50)
address_2 = forms.CharField(max_length=50)
city = forms.CharField(max_length=50)
province = forms.CharField(max_length=2)
country = forms.CharField(max_length=50)
postal_code = forms.CharField(max_length=10)
work_phone = forms.CharField(max_length=20)
mobile_phone = forms.CharField(max_length=20)
fax = forms.CharField(max_length=20)
url = forms.CharField()
comments = forms.CharField(widget=forms.Textarea)
def clean_username(self):
try:
User.objects.get(username=self.cleaned_data['username'])
except User.DoesNotExist:
return self.cleaned_data['username']
raise forms.ValidationError("Sorry, this username has already been taken. Please choose another.")
def clean_email(self):
try:
User.objects.get(email=self.cleaned_data['email'])
except User.DoesNotExist:
return self.cleaned_data['email']
raise forms.ValidationError("Sorry, this email has already been taken. Please choose another.")
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("You must type the same password each time.")
if ' ' in self.cleaned_data['username']:
raise forms.ValidationError("username must not contain spaces")
return self.cleaned_data
def save(self):
new_user = User.objects.create_user(
username = self.cleaned_data['username'],
email = self.cleaned_data['email']
)
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.set_password(self.cleaned_data['password'])
new_user.is_active = True
new_user.save()
new_profile = UserProfile(
# TODO:
)
Thanks
If you mean the permission checkboxes for is_staff and is_superuser, then you're probably best off using a ModelForm w/ the User model. This will automatically take care of everything for you.
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('last_login', 'date_joined')
EDIT per OP update: You can just add 2 forms.BooleanField() fields to your form for is_superadmin and is_staff (or name them differently), and much like you're already doing in the save method you can do new_user.is_staff = self.cleaned_data['is_staff']. You may consider using a choice field instead, w/ a dropdown w/ 3 entries, "Normal User", "Staff User", "Admin User", and then set is_staff and is_superadmin according to the user's selection.
It's also still possible to use a ModelForm on the User model and just add the necessary extra fields in addition. It may or may not be worth it to you, depending how custom you're getting.
Another note about your form - when it comes to editing existing users, this won't be able to be used for that w/ the current clean methods on username/email. But if you tweak those to exclude the current instance (if set) from the lookup, you will be able to use this form for editing existing users (though since it's not a model form you'd need to populate the initial data manually).
Related
I want to create a SINGLE form which gives the ability to the admin to create a new user with extended profile. Please note that, I don't want to use admin and registration apps.
I have extended the user with the UserProfile model. I have read all the documents related to extending user profile. But, I really don't know how to save these information.
I coded the following django form for this issue:
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField()
last_name = forms.CharField()
password1=forms.CharField(max_length=30,widget=forms.PasswordInput()) #render_value=False
password2=forms.CharField(max_length=30,widget=forms.PasswordInput())
email=forms.EmailField(required=False)
title = forms.ChoiceField(choices=TITLE_CHOICES)
def clean_username(self): # check if username dos not exist before
try:
User.objects.get(username=self.cleaned_data['username']) #get user from user model
except User.DoesNotExist :
return self.cleaned_data['username']
raise forms.ValidationError("this user exist already")
def clean(self): # check if password 1 and password2 match each other
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
raise forms.ValidationError("passwords dont match each other")
return self.cleaned_data
def save(self): # create new user
new_user=User.objects.create_user(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'],
)
return new_user
Is it OK? however it gives me an error in first_name and last_name. Says django doesn't expect first_name and last_name in save() method.
create_user only supports the username, email and password arguments. First call create_user, then add the extra values to the saved object.
new_user=User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()
I have a date time field called bk_time. Now, I would like to write custom validation for bk_time based on different users.
For example, I have users Staff_A, Staff_B and Superuser:
Staff_A can only set the time = Mon-Fri 9am-12am
Staff_B can only set the time = Monday only
Superuser no limitation
I have referred Django Doc Validators. But it seems not working for multiple validation
I have tried to write save_formsetDjango Doc Admin.But it seems not able to raise ValidationError
models.py
class Location(models.Model):
name = models.CharField('Location', max_length=100)
class Room(models.Model):
room_label = models.CharField('Room Lebel', max_length=100)
bk_time= models.DateTimeField('Booking Time')
admin.py
class RoomInline(admin.StackedInline):
model = Room
extra = 0
class LocationAdmin(admin.ModelAdmin):
list_display = ['id', 'name']
fields = ('name')
inlines = [RoomInline]
If this is relevant, I'm using Django 1.4.
I think this has to come on the form validation, and not on the field validation. This is because your validation depends on two independent fields.
In particular, this is very similar to an authentication: your validation depends on the user and on another field. Take a look how Django implements its authentication (from django.contrib.auth):
class AuthenticationForm(forms.Form):
[...]
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = authenticate(username=username,
password=password)
if self.user_cache is None:
raise forms.ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username': self.username_field.verbose_name},
)
elif not self.user_cache.is_active:
raise forms.ValidationError(
self.error_messages['inactive'],
code='inactive',
)
return self.cleaned_data
In your case, you want to raise a ValidationError on a given constraint, and return cleaned_data otherwise.
I've been trying to figure this out for hours, and believe me, I really looked everywhere on Stack Overflow.
In my UserProfile, I have a ForeignKey reference to another model (called "Company"), and upon registration, I create a new Company and point my UserProfile ForeignKey to that Company.
models.py is as follows:
class UserProfile(models.Model):
company = models.ForeignKey(Company)
title = models.CharField(max_length = 50, default = '')
user = models.OneToOneField(User, default = 0, null = True)
class Company(models.Model):
"""A company profile."""
name = models.CharField(max_length = 50)
I use a Form to do the signing up. Here's the form:
class SignupForm(ModelForm):
name = forms.CharField(label = "Name")
company = forms.CharField(max_length = 50)
email = forms.EmailField(label = "Email")
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ("name", "company", "email", "password")
def save(self, commit=True):
user = super(SignupForm, self).save(commit=False)
name = self.cleaned_data["name"].split()
if len(name) == 1:
# User did not enter a last name.
user.first_name = name
else:
user.first_name, user.last_name = name
user.email = self.cleaned_data["email"]
user.set_password(self.cleaned_data["password"])
user.username = user.email
if commit:
user.save()
return user
and here's the signup view:
def signup(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
# Check if email has already been used for an account.
email = request.POST['email']
existing_account = User.objects.filter(email = email)
if existing_account:
form = SignupForm()
return render_to_response('registration/signup.html',
{ 'form': form,
'error': 'duplicate_email',
})
# Otherwise, save the form and create a new user.
new_user = form.save()
company = Company(name=request.POST['company'])
company.save()
user_profile = new_user.get_profile()
user_profile.company = company
user_profile.save()
new_user = authenticate(
username = email,
password = request.POST['password']
)
# Log the user in automatically.
login(request, new_user)
# Redirect user to Thank You page.
return HttpResponseRedirect('/thanks')
else:
form = SignupForm()
return render_to_response('registration/signup.html', {
'form': form,
})
The error I am getting is telling me that company_id cannot be null. I clearly add a new Company. Please let me know what you think might be wrong.
Thanks
I've had this exact error today, with no reason, except that it was caused by SQLite. With SQLite, the id field of one table went from INTEGER PRIMARY KEY to INTEGER. If you're using SQLite, try deleting the offending table and recreate it with a syncdb.
What is the value of
user_profile = new_user.get_profile()
?
Not sure if this feels too hackish for your tastes but perhaps you could create/save the Company object and pass it in to your SignupForm.save() method as a positional/keyword argument.
The issue you'd get there is that you'd be expecting a CharField and you'd be passing in a company object. So you'd probably want to give company.pk to the company field in your form.
I want to create a SINGLE form which gives the ability to the admin to create a new user with extended profile. Please note that, I don't want to use admin and registration apps.
I have extended the user with the UserProfile model. I have read all the documents related to extending user profile. But, I really don't know how to save these information.
I coded the following django form for this issue:
class CreateUserForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField()
last_name = forms.CharField()
password1=forms.CharField(max_length=30,widget=forms.PasswordInput()) #render_value=False
password2=forms.CharField(max_length=30,widget=forms.PasswordInput())
email=forms.EmailField(required=False)
title = forms.ChoiceField(choices=TITLE_CHOICES)
def clean_username(self): # check if username dos not exist before
try:
User.objects.get(username=self.cleaned_data['username']) #get user from user model
except User.DoesNotExist :
return self.cleaned_data['username']
raise forms.ValidationError("this user exist already")
def clean(self): # check if password 1 and password2 match each other
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
raise forms.ValidationError("passwords dont match each other")
return self.cleaned_data
def save(self): # create new user
new_user=User.objects.create_user(username=self.cleaned_data['username'],
first_name=self.cleaned_data['first_name'],
last_name=self.cleaned_data['last_name'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'],
)
return new_user
Is it OK? however it gives me an error in first_name and last_name. Says django doesn't expect first_name and last_name in save() method.
create_user only supports the username, email and password arguments. First call create_user, then add the extra values to the saved object.
new_user=User.objects.create_user(self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.save()
I have found here on stackoverflow a method to extend django's built-in authentication using signals. My base User is defined by 'email' and passwords (so no username there). So I'm trying to modify it to my needs, but I'm geting a validation error for my form. Strange thing is that error is connected to the User.email field and I'm getting 'already in use' even though I'm just registering at the moment. Is it trying to save it 2 times or what ? I've discovered it when I was sending dictionary with data to form's contstructor in shell: form = MyForm(data={}). After this form was still invalid, but changing email to different value finally gave me True.
The user_created function connected to registration signal :
def user_created(sender, user, request, **kwargs):
form = CustomRegistrationForm(request.POST, request.FILES)
if form.is_valid():
data = UserProfile(user=user)
data.is_active = False
data.first_name = form.cleaned_data['first_name']
data.last_name = form.cleaned_data['last_name']
data.street = form.cleaned_data['street']
data.city = form.cleaned_data['city']
data.save()
else:
return render_to_response('user/data_operations/error.html', {'errors': form._errors}, context_instance=RequestContext(request))
user_registered.connect(user_created)
My form :
class CustomRegistrationForm(RegistrationForm):
first_name = forms.CharField(widget=forms.TextInput(attrs=attrs_dict), max_length=50)
last_name = forms.CharField(widget=forms.TextInput(attrs=attrs_dict), max_length=50)
street = forms.CharField(widget=forms.TextInput(attrs=attrs_dict), max_length=50)
city = forms.CharField(widget=forms.TextInput(attrs=attrs_dict), max_length=50)
My model :
class UserProfile(models.Model):
first_name = models.CharField(_("Name"), max_length=50, blank=False,)
last_name = models.CharField(_("Last name"), max_length=50, blank=False,)
street = models.CharField(_("Street"), max_length=50, blank=False,)
city = models.CharField(_("City"), max_length=50, blank=False,)
user = models.ForeignKey(User, unique=True, related_name='profile',)
Registration form :
class RegistrationForm(forms.Form):
email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
maxlength=75)),
label=_("Adres email"))
password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),
label=_("Haslo"))
password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),
label=_("Haslo powtorzone"))
def clean_email(self):
email = self.cleaned_data.get("email")
if email and User.objects.filter(email=email).count() > 0:
raise forms.ValidationError(
_(u"Already in use."))
return email
your 'user_registered' signal is sent after the User is saved. So it already has an 'email' field defined.
UPDATE
Using restless thinking :
form = CustomRegistrationForm(request.POST, request.FILES, notvalidateemail=True)
and in form :
def __init__(self, *args, **kwargs):
self.notvalidateemail = kwargs.pop('notvalidateemail',False)
super(CustomRegistrationForm, self).__init__(*args, **kwargs)
def clean_email(self):
if self.notvalidateemail:
return
else:
#your cleaning here
return email
Problem:
Your form is first saved by django-registration. Then you save it again in user_created.
Solutions:
Use a different form in user_created. One that won't have already saved fields (these from User model like email). You just want to save additional data in user_created, right?
Add some parameters to the form like:
in user_created:
form = CustomRegistrationForm(dontvalidateemail=True, request.POST, request.FILES)
and in form's init;
self.dontvalidateemail = dontvalidateemail
then just check it in clean_email.