How do I extend my Django Default UserCreationForm? - python-3.x

here is my "forms.py"
class CreateUser(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
and here is my "views.py"
def register(request):
form = CreateUser()
if request.method == 'POST':
form = CreateUser(request.POST)
if form.is_valid():
form.save()
# messages.sucess(request, 'Acccount created!')
return redirect('login')
context = {'form':form}
return render(request, 'register.html', context)
and here is my basic register.html so far.
<h3>Register</h3>
<form method="POST" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" name="Create User">
I already have a user!
{{form.errors}}
</form>
The thing is, I need to add a lot of stuff to the registration. The default user/password login is ideal, but the registration needs to have other fields for things like address and credit card number. How do I properly extend this registration, in a way that the login is still the same?

I don't know if it is the best way or similar, so I'm not sure about using Usercreationform, but I did it in my projects like this. I created a User model in my models.py, and then I just defined the fields I needed for the registerform before the meta class in the forms.py
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=30)
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField(max_length=254)
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email', 'password']

Related

How do I display error messages when I am not looping over form fields in Django templates?

My forms are not showing the error messages when I try to submit an empty form but I can see the errors while looping over the field errors in views.py. How do I overcome this problem?
the template (Updated):
{% block formcontent %}
{{form.non_field_errors}}
<div class="row">
<div class="col">
{{form.username.label_tag}} {{form.username}} {{form.username.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.first_name.label_tag}} {{form.first_name}} {{form.first_name.errors|striptags}}
</div>
<div class="col">
{{form.last_name.label_tag}} {{form.last_name}} {{form.last_name.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.email.label_tag}} {{form.email}} {{form.email.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.location.label_tag}} {{form.location}} {{form.location.errors|striptags}}
</div>
<div class="col">
{{form.designation.label_tag}} {{form.designation}} {{form.designation.errors|striptags}}
</div>
</div><br>
<div class="row">
<div class="col">
{{form.password1.label_tag}} {{form.password1}} {{form.password1.errors|striptags}}
</div>
<div class="col">
{{form.password2.label_tag}} {{form.password2}} {{form.password2.errors|striptags}}
</div>
</div><br>
{% endblock formcontent %}
Edit 1:
(Updated)
class MyRegistrationForm(UserCreationForm):
password1=forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2=forms.CharField(label='Confirm Password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model=MyRegistration
fields=['username', 'first_name', 'last_name', 'email', 'location', 'designation']
widgets={
'username':forms.TextInput(attrs={'class':'form-control'}),
'first_name':forms.TextInput(attrs={'class':'form-control'}),
'last_name':forms.TextInput(attrs={'class':'form-control'}),
'email':forms.EmailInput(attrs={'class':'form-control'}),
'location':forms.Select(attrs={'class':'form-select'}),
'designation':forms.TextInput(attrs={'class':'form-control'}),
}
def clean_username(self):
username = self.cleaned_data.get('username')
if not username:
raise ValidationError('Username is required!')
else:
try:
MyRegistration.objects.get(username=username)
raise ValidationError('This username already exists!', code='username_exists')
except MyRegistration.DoesNotExist:
pass
return username
def clean_email(self):
email=self.cleaned_data.get('email')
if not email:
raise ValidationError('Email is required!')
else:
try:
MyRegistration.objects.get(email=email)
raise ValidationError('This email already exists!', code='email_exists')
except MyRegistration.DoesNotExist:
pass
return email
def clean_first_name(self):
first_name=self.cleaned_data.get('first_name')
if not first_name:
raise ValidationError('First-name is required!')
return first_name
def clean_last_name(self):
last_name=self.cleaned_data.get('last_name')
if not last_name:
raise ValidationError('Last-name is required!')
return last_name
def clean_location(self):
location=self.cleaned_data.get('location')
if not location:
raise ValidationError('Location is required!')
return location
def clean_designation(self):
designation=self.cleaned_data.get('designation')
if not designation:
raise ValidationError('Designation is required!')
return designation
I really have no idea what is wrong with my codes in template. I have checked, the Django documentation suggests the same way to approach such scenarios where the forms are not looped over.
Edit 2:
models.py:
class MyRegistration(AbstractBaseUser, PermissionsMixin):
location_list=[
('Solapur', 'Solapur'),
('Dhule', 'Dhule'),
('Other', 'Other'),
]
username=models.CharField(max_length=10, unique=True)
email=models.EmailField(unique=True)
first_name=models.CharField(max_length=150)
last_name=models.CharField(max_length=150)
location=models.CharField(max_length=10, choices=location_list, default=None)
designation=models.CharField(max_length=70)
is_active=models.BooleanField()
is_staff=models.BooleanField(default=False)
start_date=models.DateTimeField(default=timezone.now)
last_login=models.DateTimeField(null=True)
USERNAME_FIELD='username'
REQUIRED_FIELDS=['email', 'first_name', 'last_name', 'location', 'designation']
objects=FirstManager()
def __str__(self):
return self.first_name
views.py:(Updated)
def signup(request):
print('1')
if request.user.is_authenticated:
print('2')
if request.method=='POST':
print('3')
if request.POST.get('password1')==request.POST.get('password2'):
print('4')
fm=MyRegistrationForm(request.POST)
for field in fm:
print("Field Error:", field.name, field.errors)
if fm.is_valid():
print('6')
fm.save()
messages.success(request, 'Registered successfully!!')
fm=MyRegistrationForm()
print('7')
cur_user=request.user
return render(request, 'account/signup.html', {'form':fm, 'cur_user':cur_user})
else:
fm=MyRegistrationForm()
cur_user=request.user
return render(request, 'account/signup.html', {'form':fm, 'cur_user':cur_user})
else:
return HttpResponseRedirect('/')
When you raise ValidationError in the clean method, these errors get added to the non_field_errors attribute on the form. This is why nothing gets rendered when using form.email.errors and other errors attributes on particular fields.
You should render the form.non_field_errors before you render your form, so you can see those errors, too.
However, to solve your issue, I would rather go with the option of splitting the validation of each field into particular methods clean_<field_name>. For example for username field:
def clean_username(self):
username = self.cleaned_data.get('username')
if not username:
raise ValidationError('Username is required!')
else:
try:
un=MyRegistration.objects.get(username=self.instance.username)
raise ValidationError('This username already exists!')
except MyRegistration.DoesNotExist:
pass
# Make sure you return the value of the data in
# the clean_<field_name> methods
return username
And so on for other fields, too. Doing just this should fix your code, but here are some other recommendations:
Use codes when raising ValidationErrors. E.g.: raise ValidationError('This username already exists', code='username_exists')
Check out the django-crispy package, it can handle the HTML rendering of forms with minimal code
You can set constraints in the models for unique fields (e.g. username) and required fields. This further prevents users who are not adding data with your form (e.g. admin) to add duplicate usernames or null values. This would also mean that a lot of your custom validation code would be unnecessary.
EDIT #1:
The use of instance to get the values from the submitted form is wrong. Since this form is used exclusively for create purposes as registration is creation of a new user, instance will always be empty. instance is only filled with data when you're updating a model instance.
You should replace the uses of instance with getting the form data from self.cleaned_data dict.
For example:
# Instead of:
username = self.instance.username
# Use:
username = self.cleaned_data.get('username')
EDIT #2:
After the author added the view code.
The issue might be in your view code. Also, there is no need to comparing password1 and password2 as the UserCreationForm already does that for your.
The core issue is that if your form is invalid, you need to re-render that same form, not create another instance. I propose the following update:
def signup(request):
print('1')
if request.user.is_authenticated:
print('2')
if request.method=='POST':
print('3')
form = MyRegistrationForm(request.POST)
if form.is_valid():
print('4')
form.save()
messages.success(request, 'Registered successfully!!')
# If you do this, you always render the empty form
# without the errors
# fm=MyRegistrationForm()
print('7')
cur_user=request.user
return render(
request, 'account/signup.html',
{'form': form, 'cur_user':cur_user}
)
else:
form = MyRegistrationForm()
cur_user=request.user
return render(
request, 'account/signup.html',
{'form':form, 'cur_user':cur_user}
)
else:
return HttpResponseRedirect('/')
Some other recommendations:
You probably don't need to check if the user is authenticated if this is registration view. How can the new users create an account? However, if this is needed probably the #login_required decorator works better for this.
On success, you need to redirect to the success URL. Don't use render for success scenarios, only when handling the GET method or when you need to re-render the form to display validation errors.

Upload image in Django for specific user

I am trying to upload pic for specific user but nothing happened when i select image and upload it . it not store in db and not even in media folder
setting.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL = '/media/'
View.py
def uploadPic(request):
if request.method == 'POST' and 'SESSION_KEY' in request.session:
form = Profile(
user_id=request.session['SESSION_KEY'],
profile_pic=ProfileForm(request.POST, request.FILES)
)
form.save()
return redirect('home')
else:
form = ProfileForm()
return render(request, 'upload.html', {
'form': form
})
Model.py
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(null=True, blank=True, upload_to='image/')
Form.py
class ProfileForm(forms.ModelForm):
class Meta:
model = ProfileModel
fields = ['profile_pic']
Template
{% extends 'home.html'%}
{% block content %}
{%if user.is_authenticated%}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
{% endif %}
{% endblock %}
Firstly in your form you set model = ProfileModel but your model is Profile correct that:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['profile_pic']
Next in your view in case of a POST request your view is completely wrong. You try to make an instance of Profile and call it form and save it. This is likely failing. Also I assume you write 'SESSION_KEY' in request.session in an attempt to check if the user is logged in, instead use request.user.is_authenticated or in fact disallow anonymous users from accessing your views by using the login_required decorator. Change it like so:
from django.contrib.auth.decorators import login_required
#login_required
def uploadPic(request):
if request.method == 'POST':
form = ProfileForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('home')
else:
form = ProfileForm()
return render(request, 'upload.html', {'form': form})
Note: The indentation of my answer is 4 spaces which is different from your indentation. It is best to indent by 4 spaces for readability. Check about indentation in PEP 8 which is the Style Guide for Python Code.

Custom Django-Allauth SignUp form not adding new users

I tried to create a custom Signup Form with allauth but when I submit the form on the frontend it directs to the success_url and upon inspection in the admin panel a new user wasn't created.
# forms.py
from allauth.account.forms import SignupForm
class SimpleSignupForm(SignupForm):
mobile_number = PhoneNumberField(required=True)
first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}), max_length=255, required=True)
last_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}), max_length=255, required=True)
address = AddressField(required=True)
type = forms.ModelChoiceField(queryset=UserType.objects.all())
def save(self, request):
user = super(SimpleSignupForm, self).save(request)
user.mobile = self.cleaned_data['mobile_number']
user.address = self.cleaned_data['address']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.type = self.cleaned_data['type']
user.save()
return user
def __init__(self, *args, **kwargs):
super(SimpleSignupForm, self).__init__(*args, **kwargs)
visibles = self.visible_fields()
visibles[0].field.widget.attrs['class'] = 'form-control'
# settings.py
ACCOUNT_FORMS = {'signup': 'my_app_path.forms.SimpleSignupForm'}
On the template file I made sure the <form> tag has method='POST' and that I included {% csrf_token %} in the form. The button is also a a submit type. I've also made sure {{ form.as_p }} has all the required fields when submitting. There are no errors or warnings popping up anywhere.
I hope this helps. I will recommend you use Signup method instead of Save
class CustomSignupForm(forms.Form):
first_name = forms.CharField(max_length=30, label='First Name')
last_name = forms.CharField(max_length=30, label='Last Name')
def __init__(self, *args, **kwargs):
super(CustomSignupForm, self).__init__(*args, **kwargs)
self.fields['first_name'].widget.attrs['placeholder'] = 'First Names'
self.fields['last_name'].widget.attrs['placeholder'] = 'Last Names'
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()

Django - Updating multiple models from a form - Data does not saved

I have a custom User model to manage some profiles user: is_student, is_professor and is_executive
In this model, in addition, I have the get_student_profile(),get_professor_profile() and get_executive_profile() methods to get the user profiles data of each user from my different views.
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False)
is_professor = models.BooleanField(default=False)
is_executive = models.BooleanField(default=False)
def get_student_profile(self):
student_profile = None
if hasattr(self, 'studentprofile'):
student_profile = self.studentprofile
return student_profile
def get_professor_profile(self):
professor_profile = None
if hasattr(self, 'professorprofile'):
professor_profile = self.professorprofile
return professor_profile
def get_executive_profile(self):
executive_profile = None
if hasattr(self, 'executiveprofile'):
executive_profile = self.executiveprofile
return executive_profile
In addition each profile user is_student, is_professor and is_executive have their own model in where I manage their own data:
class StudentProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
origin_education_school = models.CharField(max_length=128)
current_education_school = models.CharField(max_length=128)
extra_occupation = models.CharField(max_length=128)
class ProfessorProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
class ExecutiveProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
Is of this way that in my User model I override the save() method to denote that the username field of an user which is created, to be equal in their value to the slug belonging to the profile user which will take that user (StudentProfile, ProfessorProfile, ExecutiveProfile):
def save(self, *args, **kwargs):
user = super(User,self).save(*args,**kwargs)
# Creating an user with student, professor and executive profiles
if self.is_student and not StudentProfile.objects.filter(user=self).exists() \
and self.is_professor and not ProfessorProfile.objects.filter(user=self).exists() \
and self.is_executive and not ExecutiveProfile.objects.filter(user=self).exists():
student_profile = StudentProfile(user=self)
student_slug = self.username
student_profile.slug = student_slug
professor_profile = ProfessorProfile(user=self)
professor_slug = self.username
professor_profile.slug = professor_slug
executive_profile = ExecutiveProfile(user=self)
executive_slug = self.username
executive_profile.slug = executive_slug
student_profile.save()
professor_profile.save()
executive_profile.save()
# And so for all possibles profile combinations
To these three profiles which I have three forms in where their own fields are generated
class StudentProfileForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = ('origin_education_school', 'current_education_school',
'extra_occupation')
class ProfessorProfileForm(forms.ModelForm):
class Meta:
model = ProfessorProfile
fields = ('occupation',)
class ExecutiveProfileForm(forms.ModelForm):
class Meta:
model = ExecutiveProfile
fields = ('occupation', 'enterprise_name', 'culturals_arthistic','ecological')
I access to view profile to user through of this URL:
url(r"^profile/(?P<slug>[\w\-]+)/$",
views.account_profiles__update_view,
name='profile'
),
In my function based view account_profiles__update_view() I am managing the request of the user, and creating the form instances (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm) according to the profile to user (is_student, is_professor and is_executive)
#login_required
def account_profiles__update_view(request, slug):
user = request.user
# user = get_object_or_404(User, username = slug)
# empty list
_forms = []
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
# user = get_object_or_404(settings.AUTH_USER_MODEL, username = slug)
if request.method == 'POST':
# Create a list with all formularies in which there is some POST
# operation. This mean if there is one, two or three profiles together
# or individual
formularios =[Form(data = request.POST,instance=profile) for Form in _forms]
if all([form.is_valid() for form in formularios]):
# Only save dato to database if all formularies that send
# the user in their request are correct or well formed in their
# data. Check that all formularies has been filled
for form in formularios:
profile = form.save(commit=False)
profile.user = user
profile.save()
return redirect('dashboard')
else:
formularios = [Form() for Form in _forms]
# Access to class Forms instanced (StudentProfileForm,
# ProfessorProfileForm, ExecutiveProfileForm), through the __class__
# pŕoperty which return the class onlying. An this class have another
# property named __name__ which return the name of string of a class,
# which is the same name with I did name the form classes
# (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm)
# Next I call to their string method to grant that I always will return
# a string and I call to lower.
# The idea with this is place data into a python dictionarie and access
# to it
data = {form.__class__.__name__.__str__().lower(): form for form in formularios}
data['userprofile'] = profile
return render(request, 'accounts/profile_form.html', data,)
And my profile_form.html template I have the following small logic:
<form method="POST">
{% csrf_token %}
{% if userprofile.user.is_student %}
<div align="center"><i>My Student Profile data</i></div>
{% bootstrap_form studentprofileform %}
{{ studentprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_professor %}
<div align="center"><i>My Professor Profile data</i></div>
{% bootstrap_form professorprofileform %}
{{ professorprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_executive %}
<div align="center"><i>My Executive Profile data</i></div>
{% bootstrap_form executiveprofileform %}
{{ executiveprofileform.non_field_errors }}
{% endif %}
<input type="submit" value="Save Changes" class="btn btn-default">
</form>
I wanted to write all these details to comment the following situation which happen to me:
I render the three forms in my template
Only store data related to the latest user profile selected, this mean:
profiles: is_student, is_professor and is_executive
User with is_student profile ... Save data
User with is_professor profile ... Save data
User with is_executive profile ... Save data
User with is_student and is_professor profile: Only save data to is_professor profile. Does not save data in is_student profile forms fields
User with is_student and is_executive profile: Only save data to is_executive profile. Does not save data in is_student profile forms fields
User with is_professor and is_executive profile: Only save data to is_executive profile. Does not save data in is_professor profile forms fields
User with is_student, is_professor and is_executive profiles: Only save data to is_executive profile. Does not save data in is_professor and is_student profile forms fields
In this moment, only is taked in account the latest selected profile user and according to it, save their related data and not other.
This is because in my account_profiles__update_view() function based view I have this if .. sentences logic:
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
But, I unknown if I will should consider perform here all the profiles user combinations possibles and create the same combination of form instances possibles too. Is this factible of perform?
I try perfom account_profiles__update_view() as a class based view, here some code about it but the characterization of profiles and instances forms send to the template, make me that I choose the function based view option.
¿What is the best alternative?
My apologies for the long question, I did want give all details for to better understanding of my code and approach that I want accomplish.
I appreciate highly some support and orientation.
I took the liberty of cleaning some stuff up for you. Let's review each piece.
models.py
There's no need to probe the model with hasattr(). We can rather use the fact that the OneToOneField between a User and a Profile will place a reference on both sides of the relation. This means you can simply override your save() method as follows:
Note: You may rather want to create the Profiles using Signals instead.
from django.conf import settings
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False, help_text="User is student")
is_professor = models.BooleanField(default=False, help_text="User is professor")
is_executive = models.BooleanField(default=False, help_text="User is executive")
USERNAME_FIELD = 'email'
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
if self.is_student and getattr(self, 'studentprofile', None) is None:
StudentProfile.objects.create(
user=self,
slug=self.username
)
if self.is_professor and getattr(self, 'professorprofile', None) is None:
ProfessorProfile.objects.create(
user=self,
slug=self.username
)
if self.is_executive and getattr(self, 'executiveprofile', None) is None:
ExecutiveProfile.objects.create(
user=self,
slug=self.username
)
views.py
Again, let's just use the fact that the OneToOneField on a user will contain a reference to the Profile:
#login_required
def update_view(request):
user = request.user
# Populate Forms and Instances (if applicable)
form_profiles = []
if user.is_student:
form_profiles.append({'form': StudentProfileForm, 'instance': user.studentprofile})
if user.is_professor:
form_profiles.append({'form': ProfessorProfileForm, 'instance': user.professorprofile})
if user.is_executive:
form_profiles.append({'form': ExecutiveProfileForm, 'instance': user.executiveprofile})
if request.method == 'POST':
forms = [x['form'](data=request.POST, instance=x['instance']) for x in form_profiles]
if all([form.is_valid() for form in forms]):
for form in forms:
form.save()
return redirect('dashboard')
else:
forms = [x['form'](instance=x['instance']) for x in form_profiles]
return render(request, 'accounts/profile_form.html', {'forms': forms})
forms.py
Your forms may look something like this:
class StudentProfileForm(forms.ModelForm):
title = "Student Form"
class Meta:
model = StudentProfile
fields = (
'origin_education_school',
'current_education_school',
'extra_occupation',
)
profile_form.html
<form method="post">
{% csrf_token %}
{% for form in forms %}
<h1>{{ form.title }}</h1>
{{ form }}
{% endfor %}
<button type="submit">Submit</button>
</form>
I double-checked, and forms are saved correctly.
P.S. If you would like to use a Class-Based View, you can follow the classes defined by this Gist: https://gist.github.com/michelts/1029336

Edit user profiles form without using django admin

I am developing a simple LMS system where I have 3 stakeholders Administrator, Faculty Members and Students. Administrator can create, edit, delete, block and list user accounts, with my developement so far I am able to create and list all users.
Now I am stuck at editing user profile, my requirement is when I click on any listed users it should open my extended/customized user profile in a form and I should have the ability to edit any opened user profile.
Below are my code snippets:
MODELS.PY:
from django.contrib.auth.models import User
class UserInformation(models.Model):
user = models.ForeignKey(User, unique=True)
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
def __str__(self):
return self.user.username
VIEWS.PY (to create user):
def ad_create_user(request):
if request.method == 'POST':
firstname = request.POST['firstname']
lastname = request.POST['lastname']
username = request.POST['username']
password = request.POST['password']
email = request.POST['email']
group = request.POST['group']
degree = request.POST['degree']
cell_no = request.POST['cell_no']
new_user = User.objects.create_user(username, email, password)
new_user.first_name = firstname
new_user.last_name = lastname
new_user.save()
if group == 'option_one':
set_group = 3
new_user.groups.add(3)
userinfo = UserInformation(user=User.objects.get(username=username), degree=Degree.objects.get(pk=degree),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_two':
set_group = 2
new_user.groups.add(2)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_three':
set_group = 1
new_user.groups.add(1)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
return HttpResponseRedirect('/administrator/user_management/')
return render(request, 'MobiApp/create_user.html', {'form': CreateUserForm()})
FORMS.PY (to create user):
class CreateUserForm(forms.Form):
firstname = forms.CharField(max_length=64)
lastname = forms.CharField(max_length=64)
username = forms.CharField(max_length=16)
password = forms.CharField(
widget=forms.PasswordInput(),
)
email = forms.EmailField()
group = forms.ChoiceField(
choices=(
('option_one', "Student"),
('option_two', "Faculty Member"),
('option_three', "Administrator"),
),
widget = forms.RadioSelect,
initial = 'option_one',
)
degree = forms.ModelChoiceField(queryset=Degree.objects.all())
cell_no = forms.CharField()
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.layout = Layout(
Field('firstname', css_class='input-xlarge'),
Field('lastname', css_class='input-xlarge'),
Field('username', css_class='input-xlarge'),
Field('password', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
'group',
'degree',
Field('cell_no', css_class='input-xlarge'),
FormActions(
Submit('create', 'Create!', css_class="btn-primary"),
)
)
I found many questions similar to this but none of them helped me and my requirement is also little different as user is not editing his/her profile but administrator is editing profile of any user.
Just for your information:
I am using Django-Crispy-Forms
When I click on any user of edit profile, its URL will be something like this http://myapp.com/administrator/edit_user/11
where 11 is the user id
Thanks in advance, let me know if you need any further information.
EDIT:Here's my final proposed solution (charlesliam also made a reference to this in his comment)
We will subclass AbstractUser to add extra fields to the user. Obviously, there's other ways of doing this, but using AbstractUser should suffice your requirements. You'd have to syncdb for model changes to propagate.
SETTINGS.PY
AUTH_USER_MODEL = 'app.UserInformation' # Points to our custom User model which we will define in models.py
MODELS.PY
from django.contrib.auth.models import AbstractUser
class UserInformation(AbstractUser):
# user = models.ForeignKey(User, unique=True) <---- Remove this field
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
FORMS.PY
class EditUserForm(forms.ModelForm): #fixed typo. It's forms.ModelForm, not models.ModelForm
class Meta:
model = UserInformation
VIEWS.PY
from forms.py import EditUserForm
def edit_user (request, id):
user = User.objects.get(id=11)
if request.method == 'POST': #If form has been submitted
form = EditUserForm(request.POST, instance=user)
if form.is_valid(): #All good. Validation passed
form.save()
return HttpResponseRedirect('/your-view/') # Redirect after POST
else:
form = EditUserForm(instance=user) # Unbound form
return render(request, 'MobiApp/edit_user.html', {'form': form})
edit_user.html
{% load crispy_forms_tags %}
{% crispy form %}
will give you a pre-populated form with the user instance, which you can edit and POST back.
Now with regards to user authentication, you can check if the currently logged in user is superuser (administrator), and proceed with the form editing logic.
So in your VIEWS.PY:
def edit_user (request, id):
current_user = request.user
if current_user.is_superuser:
...
Alternatively, you can assign the currently logged-in user to any group and then check if the user is member of that group, then proceed with form editing.
I hope that helps.
REFERENCES:
https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/
https://github.com/django/django/blob/master/django/contrib/auth/models.py#L353
https://docs.djangoproject.com/en/dev/topics/auth/customizing/
When to use the Custom User Model in Django 1.5

Resources