I need add the first_name and last_name fields associated with
that User model and display it in the profile form.
fields:
>>> user = User.objects.get(pk=1)
>>> user.first_name
u'Some'
>>> user.last_name
u'User'
My model is something like this :
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
personal_email = models.EmailField(blank=True)
address = models.CharField(max_length=140)
phone_number = models.CharField(max_length=20)
def __unicode__(self):
return u'Profile of user: %s' % self.user.username
when rendering the profile form, would have to show the fields.
first_name:
last_name:
personal_email:
address:
phone_number:
Edit
I resolved to:
#forms.py
class UserProfileForm(forms.ModelForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
self.fields['first_name'].initial = self.instance.user.first_name
self.fields['last_name'].initial = self.instance.user.last_name
self.fields.keyOrder = [
'first_name',
'last_name',
'personal_email',
'address',
'phone_number',
]
def save(self, *args, **kwargs):
super(UserProfileForm, self).save(*args, **kwargs)
self.instance.user.first_name = self.cleaned_data.get('first_name')
self.instance.user.last_name = self.cleaned_data.get('last_name')
self.instance.user.save()
class Meta:
model = UserProfile
#urls.py
url(r'^profiles/edit/', edit_profile, {'form_class': UserProfileForm},
name='profiles_edit_profile' ),
and add in #signals.py
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
userprofile, new = UserProfile.objects.get_or_create(user=instance)
Assuming you are using a ModelForm you could do the following:
class profileForm(ModelForm):
first_name = forms.CharField(max_length=30, required=False)
last_name = forms.CharField(max_length=30, required=False)
class Meta:
model = UserProfile
def save(self, commit=True):
m = super(customerForm, self).save(commit=False)
# Update and save user model here
if commit:
m.save()
return m
You could skip overriding the save methods and do the save in your view. Just get get the first and last name value and save it after you validate the form. You might also want to used a transaction to make sure everything saves or nothing does.
Related
I am working on Hospital Management System and there are 5-6 different types of users like Patient, Doctor, Nurse, Accountant, Receptionist, etc. I've extended the User model using AbstractUser which has common fields for all users like DoB, address, etc.
models.py
class User(AbstractUser):
# user_type = models.CharField(choices=USER_TYPES, default='patient', max_length=20)
date_of_birth = models.DateField(blank=True, null=True, validators=[validate_future_date])
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+9199999999'. Up to 15 digits allowed.")
mobile_num = models.CharField(max_length=15, validators=[phone_regex])
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
date_joining = models.DateTimeField(auto_now_add=True)
photo = models.ImageField(default="default.png", upload_to="patients/%Y/%m/%d", blank=True)
# other fields
def __str__(self):
return f"{self.first_name} {self.last_name}({self.username})"
class Staff(models.Model):
aadhar_number = models.BigIntegerField(verbose_name='Aadhar Number')
empCategory = models.CharField(max_length=20, blank=True, verbose_name='Employee Category')
class Meta:
abstract = True
class Patient(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date_of_discharge = models.DateTimeField(auto_now=True)
allergies = models.TextField(blank=True, null=True)
def __str__(self):
return f"{self.user.first_name} {self.user.last_name}({self.user.username})"
class Doctor(models.Model):
DEPARTMENTS = [('Cardiologist', 'Cardiologist'),
('Dermatologists', 'Dermatologists'),
('Emergency Medicine Specialists', 'Emergency Medicine Specialists'),
('Allergists/Immunologists', 'Allergists/Immunologists'),
('Anesthesiologists', 'Anesthesiologists'),
('Colon and Rectal Surgeons', 'Colon and Rectal Surgeons')
]
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
languages = models.CharField(max_length=20)
speciality = models.CharField(max_length=20)
department = models.CharField(max_length=50, choices=DEPARTMENTS)
# patients = models.ManyToManyField(Patient, related_name='doctors')
def __str__(self):
return f"{self.user.first_name} {self.user.last_name}({self.user.username})"
class Receptionist(Staff):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# patient = models.ManyToManyField(Patient, related_name='receptionists', blank=True)
def __str__(self):
return f"{self.user.first_name}"
class Nurse(Staff):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'Nurses'
class Accountant(Staff):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput)
email = forms.EmailField(label='Email')
date_of_birth = forms.DateField(widget=forms.widgets.DateInput(attrs={'type': 'date'}))
class Meta:
# gives current active model either Custom User or default User model
model = get_user_model()
fields = ['username', 'first_name', 'last_name', 'email',
'date_of_birth', 'photo', 'mobile_num', 'gender',
'father_name', 'mother_name', 'blood_group', 'marital_status',
'address1', 'address2', 'city', 'zipcode', 'state'
]
exclude = ['groups', 'superuser_status',
'is_staff', 'is_superuser', ]
def clean_password2(self):
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError("Passwords don't match")
return cd['password2']
class PatientRegistrationForm(forms.ModelForm):
class Meta:
model = Patient
fields = ['allergies']
exclude = ['user', ]
views.py
class UserRegistrationMixin(TemplateResponseMixin, View):
form_class = UserRegistrationForm
template_name = 'accounts/register.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user_form'] = self.form_class
return context
def get(self, request):
user_form = self.form_class
return self.render_to_response({'user_form':user_form})
def post(self, request):
user_form = self.form_class(data=request.POST, files=request.FILES)
if user_form.is_valid():
new_user = user_form.save(commit=False)
password = user_form.cleaned_data['password']
new_user.set_password(password)
new_user.save()
messages.success(request, f'New user "{new_user}" created!')
return self.render_to_response({'user_form':user_form})
class PatientRegistrationView(UserRegistrationMixin, CreateView):
profile_form_class = PatientRegistrationForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['profile_form'] = self.profile_form_class
return context
def get(self, request):
profile_form = self.profile_form_class
return self.render_to_response({'profile_form':profile_form})
def post(self, request):
profile_form = self.profile_form_class(data=request.POST, files=request.FILES)
if profile_form.is_valid():
# Patient.objects.create()
profile = profile_form.save(commit=False)
profile.user = new_user
profile.save()
messages.success(request, f'Profile for user "{new_user}" created!')
return self.render_to_response({'profile_form':profile_form})
I am trying to separate common logic for registering users and creating profiles for each user i.e. UserRegistrationMixin has logic to create a user and PatientRegistrationView will create a patient's profile and its permissions. But when I inherit from UserRegistrationMixin, user_form doesn't show. I don't have much experience in Django's GCBV. Thanks in advance.
The problem is your get method. The get_context_data doesn't called. You can check the get method of View class:
def get(self, request, *args, **kwargs):
"""Handle GET requests: instantiate a blank version of the form."""
return self.render_to_response(self.get_context_data())
You can call context = self.get_context_data() and pass the context to render_to_response.
I wrote my own form for editing of profile and need to save ip of user, who edit profile, but not really understand how to do this. I know, that ip we can get from request.META['REMORE_ADDR'] but where to put this and how to save to my db... Will be very glad if you could help.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, unique=True)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
date_of_birth = models.DateField()
biography = models.TextField()
contacts = models.CharField(max_length=200)
ip_address = models.GenericIPAddressField(null=True)
forms.py
class UserEditProfile(forms.ModelForm):
first_name = forms.CharField( max_length=30)
last_name = forms.CharField( max_length=30)
date_of_birth =
forms.DateField(widget=SelectDateWidget(years=BIRTH_YEAR_CHOICES))
biography = forms.Textarea()
contacts = forms.CharField()
def __init__(self, *args, **kw):
super(UserEditProfile, self).__init__(*args, **kw)
self.fields['first_name'].initial = self.instance.first_name
self.fields['last_name'].initial = self.instance.last_name
self.fields['date_of_birth'].initial =
self.instance.date_of_birth
self.fields['biography'].initial = self.instance.biography
self.fields['contacts'].initial = self.instance.contacts
self.fields.keyOrder = [
'first_name',
'last_name',
'date_of_birth',
'biography',
'contacts'
]
def save(self, *args, **kw):
super(UserEditProfile, self).save(*args, **kw)
self.instance.first_name = self.cleaned_data.get('first_name')
self.instance.last_name = self.cleaned_data.get('last_name')
self.instance.date_of_birth =
self.cleaned_data.get('date_of_birth')
self.instance.biography = self.cleaned_data.get('biography')
self.instance.contacts = self.cleaned_data.get('contacts')
self.instance.save()
class Meta:
model = Profile
fields = (
'first_name',
'last_name',
'date_of_birth',
'biography',
'contacts'
)
exclude = ['user', 'ip_address']
view.py
def edit_profile(request):
user = Profile.objects.get(id=request.user.id)
if request.method == "POST":
form = UserEditProfile(request.POST, instance=user)
if form.is_valid():
form.save(commit=False)
return redirect('profile')
else:
form = UserEditProfile(instance=user)
args = {'form': form}
return render(request, 'edit.html', args)
You cannot pass request object into form directly. That's not the way it works. If you need to associate any request attributes to your model instances, you should do it in the views.
You could collect the request.META['REMOTE_ADDR'] which gives the IP info of the logged in user in the view and associate it to yourinstance` in the view itself.
You could do this in your form.is_valid() method,
if form.is_valid():
profile = form.save(commit=False)
profile.ip_address = request.META['REMOTE_ADDR']
profile.user = request.user
profile.save()
return redirect('profile')
This code works perfectly, which is a User model with one to many relationship with UserRating model.
View:
def index(request):
user_list = User.objects.order_by('-userrating')[:5]
city_list = City.objects.order_by('-name')[:5]
context_dict = {"users": user_list, "cities" : city_list}
return render(request, "index.html", context_dict)
Models:
# this is model for user
class User(models.Model):
username = models.CharField(max_length=128, unique=True)
email = models.EmailField(max_length=128, unique=True)
profilepic = models.ImageField(null=True)
firstname = models.CharField(max_length=128, null=True)
secondname = models.CharField(max_length=128, null=True)
city = models.ForeignKey(City)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
# Uncomment if you don't want the slug to change every time the name changes
# if self.id is None:
# self.slug = slugify(self.name)
self.slug = slugify(self.username)
super(User, self).save(*args, **kwargs)
def __unicode__(self):
return self.username
#property
def avg_rating(self):
return self.userrating_set.all().aggregate(Avg('rating'))['rating__avg']
# this is the model for user ratings - one to many relationship with User
class UserRating(models.Model):
user = models.ForeignKey(User)
comment = models.CharField(max_length=500)
for_username = models.CharField(max_length=128)
rating = models.IntegerField(default=5)
def __unicode__(self):
return unicode(self.rating)
However, it breaks once I use Django's built in User model as below (User model with one to one relationship with a UserProfile model and a one to many relationship with UserRating)
# this is model for user
class UserProfile(models.Model):
user = models.OneToOneField(User)
profilepic = models.ImageField(blank=True)
city = models.ForeignKey(City)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.user.username)
super(User, self).save(*args, **kwargs)
def __unicode__(self):
return self.user.username
#property
def avg_rating(User):
return self.userrating_set.all().aggregate(Avg('rating'))['rating__avg']
# this is the model for user ratings - one to many relationship with User
class UserRating(models.Model):
user = models.ForeignKey(User)
comment = models.CharField(max_length=500)
for_username = models.CharField(max_length=128)
rating = models.IntegerField(default=5)
def __unicode__(self):
return unicode(self.rating)
it generates this error when adding a user profile via admin page:
super(type, obj): obj must be an instance or subtype of type
You must call the actual superclass in your super call; it is UserProfile, not User.
def save(self, *args, **kwargs):
self.slug = slugify(self.user.username)
super(UserProfile, self).save(*args, **kwargs)
Hi i need add request user pk to UserCreationForm. I try many times, but with out results. In my dashboard i have user owner and i have user seller.
One model for all 3 types user. So Owner can create another user with role=seller, but for this i need add parent field with param=request.user.pk to seller
Custom UserModel
from django.db import models
from django.contrib.auth.models import AbstractUser
USER = 0
OWNER = 1
SELLER = 2
user_type_choice = (
(USER, 'User'),
(OWNER, 'Owner'),
(SELLER, 'Seller'),
)
class User(AbstractUser):
role = models.CharField(max_length=100, choices=user_type_choice, default=USER)
idn = models.CharField(max_length=10, blank=True, default=None, null=True)
mobile = models.CharField(max_length=15, blank=True, default=None, null=True)
parent = models.ForeignKey('self', null=True, blank=True)
tariff = models.IntegerField(default=None, null=True, blank=True)
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
forms.py
class SellerRegisterForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2') """try add and remove 'parent' here in felds """
def save(self, commit=True):
user = super(SellerRegisterForm, 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']
user.role = ROLE_SELLER
# try add user.parent = self.request.user.pk
# but it does not work
if commit:
user.save()
return user
views.py
def register_seller(request):
if request.method == 'POST':
form = SellerRegisterForm(request.POST) # create form object
if form.is_valid():
#try add new_form = form.save(commit=False)
# new_form.parent = request.user.pk
# new_form.save() but it not working
form.save()
return HttpResponseRedirect('/accounts/login')
else:
form = SellerRegisterForm()
return render(request, 'register_owner.html', {'form': form})
You need to pass the user object through the form's __init__ method.
class SellerRegisterForm(UserCreationForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(SellerRegisterForm, self).__init__(*args, **kwargs)
and in your view:
form = SellerRegisterForm(request.POST, user=request.user)
Then simply use self.user anywhere in your form class.
Im extending the django User model with User profile like this :
class UserProfile(BaseModel):
user = models.ForeignKey(User, unique=True, related_name="profile")
city = models.CharField(_("City"), max_length=200)
tel = models.CharField(_("Phone Number"), max_length=50,
help_text=_("(+ Country Code) (Area Code) (Your phone number)"))
description = models.TextField(null=True, blank=True,
help_text = _("Small description about yourself."))
photo = models.ImageField(max_length=255, upload_to="profiles/")
def __unicode__(self):
return "%s %s" % (self.user.first_name, self.user.last_name)
def profile_image(self):
return settings.DEFAULT_PROFILE_IMAGE
and this is the form Im using on the front end in order to edit the profile from there:
class UserProfileForm(forms.ModelForm):
# uniForm Helper
helper = FormHelper()
helper.form_id = "edit_profile_form"
helper.form_class = 'mlForm'
layout = Layout(
Fieldset('',
'country', 'city',
'tel', 'photo', 'description',
)
)
helper.add_layout(layout)
# Submit button(s)
submit = Submit('submit','Submit')
helper.add_input(submit)
cancel = Submit('cancel','Cancel')
helper.add_input(cancel)
class Meta:
model = UserProfile
fields = ['city',
'tel', 'photo', 'description',]
def __init__(self, request, *args, **kw):
super(UserProfileForm, self).__init__(*args, **kw)
self.request = request
def save(self, *args, **kw):
edit_profile_form = super(UserProfileForm, self).save(*args, **kw)
return edit_profile_form, "User successfully modified."
What I want to do is add the User email field in the form so that the user can also edit this field from the frontend.
How would I do that?
Hope, this will help
class UserProfileForm(forms.ModelForm):
email = forms.EmailField(label=u'Email address',required=True)
class Meta:
model = UserProfile
exclude = ['user',]
def __init__(self, *args, **kw):
super(UserProfileForm, self).__init__(*args, **kw)
self.fields['email'].initial = self.instance.user.email
self.fields.keyOrder = ['your','fields','you','want','to','display','including','email']
def save(self, *args, **kw):
super(UserProfileForm, self).save(*args, **kw)
self.instance.user.email = self.cleaned_data.get('email')
self.instance.user.save()
this recipe works for me (django 1.3).
in views.py must be something like this:
def profile(request,id):
if request.method == 'POST':
user = get_object_or_404(User,pk=id)
profile = user.profile
form = UserProfileForm(data = request.POST,instance = profile)
if form.is_valid():
form.save()
Send the two objects-forms (UserEditForm and UserProfileForm) into the template form and submit them together.