Update user profile with user uuid - python

I want to update user profile passing user uuid as kwarg.
Here is the url:
path("profile/update/<uuid:pk>", UpdateProfile.as_view(), name="update_profile"),
However, after I try to update my profile, it gives me an error.
Here is my view:
class UpdateProfile(LoginRequiredMixin, UpdateView):
model = Profile
user_type_fields = {
"Buyer": ["photo", "first_name", "last_name", "city"],
"Celler": ["photo", "name", "city", "address"],
}
def get(self, request, *args, **kwargs):
print(kwargs)
self.fields = self.user_type_fields[get_user_model().objects.get(pk=kwargs["pk"]).type]
return super().get(request, *args, **kwargs)
And here is the error itself:
Page not found (404)
No profile found matching the query
As I understand, django tries to find profile with uuid as in url, doesn't find it and returns me this error. However, if I change model in my view to user, it wouldn't be able to find fields as they belong to profile model. The only working option was to pass profile id as kwarg, but I don`t find it preferrable due to security reasons.
Could someone give me an advice on how to update profile with user uuid in kwargs?
Thanks in advance!
UPD:
Here are User and Profile models:
class CustomUser(AbstractBaseUser, PermissionsMixin):
class UserTypeChoices(models.TextChoices):
SINGLE_VOLUNTEER = "Single Volunteer", _("Single Volunteer")
VOLUNTEERS_ORGANISATION = "Volunteers Organisation", _("Volunteers Organisation")
CIVIL_PERSON = "Civil Person", _("Civil Person")
MILITARY_PERSON = "Military Person", _("Military Person")
type = models.CharField(
max_length=23,
choices=UserTypeChoices.choices,
)
uuid = models.UUIDField(
primary_key=True,
default=uuid4,
unique=True,
db_index=True,
editable=False,
)
email = models.EmailField(
_("email address"),
null=True,
blank=True,
)
phone = PhoneNumberField(
_("phone"),
null=True,
blank=True,
)
is_staff = models.BooleanField(
_("staff status"),
default=False,
help_text=_("Designates whether the user can log into this admin site."),
)
is_active = models.BooleanField(
_("active"),
default=True,
help_text=_(
"Designates whether this user should be treated as active. " "Unselect this instead of deleting accounts."
),
)
def __str__(self):
if self.email:
return str(self.email)
else:
return str(self.phone)
USERNAME_FIELD = "email"
objects = CustomUserManager()
class Profile(models.Model):
user = models.OneToOneField(to="accounts.CustomUser", on_delete=models.CASCADE, blank=True, null=True)
photo = models.ImageField(upload_to="profile/", blank=True, null=True, default="profile/profile_default.png")
name = models.CharField(_("name"), max_length=150, blank=True, null=True, default=None)
first_name = models.CharField(_("first name"), max_length=150, blank=True, null=True, default=None)
last_name = models.CharField(_("last name"), max_length=150, blank=True, null=True, default=None)
city = models.CharField(_("city"), max_length=150, blank=True, null=True, default=None)
address = PlainLocationField()
def __str__(self):
if self.user.email:
return str(self.user.email)
else:
return str(self.user.phone)

Assuming the following model, where a user only has one profile:
class Profile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
photo = models.ImageField()
# ... your other fields
You can then overwrite the get_object() method:
class UpdateProfile(LoginRequiredMixin, UpdateView):
model = Profile
fields = ['photo', '...']
def get_object(self):
user = get_user_model().objects.get(pk=self.kwargs['pk'])
profile = user.profile
return profile
And then use the UpdateView as normal.

Related

How to get logged in user in django from custom users model

I want to get username from custom users model
My Custom Users model:
class Account(AbstractBaseUser, PermissionsMixin):
nickname = models.CharField(max_length=150, unique=True)
name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
phone = models.CharField(max_length=50, unique=True)
date_of_birth = models.DateField(blank=True, null=True)
picture = models.ImageField(blank=True, null=True)
is_staff = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
last_login = models.DateTimeField(null=True)
admin_of_company = models.ForeignKey('companies.company', on_delete=models.CASCADE, default=None, blank=True,
null=True)
objects = AccountManager()
USERNAME_FIELD = 'nickname'
REQUIRED_FIELDS = ['name', 'last_name', 'phone']
def get_full_name(self):
return self.name, self.last_name
def get_short_name(self):
return self.name.split()[0]
and products model:
class products(models.Model):
name = models.CharField(max_length=150)
about = models.TextField()
price = models.IntegerField()
picture = models.ImageField(default=None)
admin = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
in products.admin I want to set default logged in user
but I don't know how to get this data from custom users model
If you would like to get a current account in your view use this
current_user_id = self.request.user.id
current_account = Account.objects.get(pk=current_user_id)
current_account_nickname = current_account.nickname
Your model Account doesn't have "username" field.
You have to add it if you would like to use "username".
class Account(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=150, unique=True)

Django User model saves twice into database

I am trying to create multi user registration system with Django. However, anytime I call the save() method to save a User type, it saves into the User table twice. The funny thing about the second model that is saved is that many required fields are empty.
I am using a custom user model that I created from AbstractBaseUser. I also rewrote the forms for the CustomUser model. For the multiple user types, I am using a profile model (Student model has a OneToOne field to the user model)
models.py:
class User(AbstractBaseUser, PermissionsMixin):
# I've removed some unimportant code here
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
class Types(models.TextChoices):
STUDENT = 'STUDENT', 'Student'
DEPARTMENT_USER = 'DEPARTMENT_USER', 'Department user'
ADMIN = 'ADMIN', 'Admin'
user_type = models.CharField(_('Type'), max_length=50, choices=Types.choices, default=Types.STUDENT)
first_name = models.CharField(_('First name'), max_length=70, blank=False, default="")
middle_name = models.CharField(_('Middle name'), max_length=70, blank=True, default="")
last_name = models.CharField(_('Last name'), max_length=70, blank=False, default="")
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False) # a admin user; non super-user
is_superuser = models.BooleanField(default=False) # a superuser
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['user_type', 'first_name', 'last_name'] # Email & Password are required by default.
objects = UserManager()
class Meta:
verbose_name = ('user')
verbose_name_plural = ('users')
#db_table = 'auth_user'
abstract = False
class AccountConfirmed(models.Model):
# Model to determine which users have confirmed their email addresses.
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='accountconfirmed')
email_confirmed = models.BooleanField(default=False)
reset_password = models.BooleanField(default=False)
class Meta:
app_label = 'auth'
# When the user model is created, through signals an AccountConfirmed model is also created.
# The email_confirmed and reset_password field is set to false.
#receiver(models.signals.post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
AccountConfirmed.objects.create(user=instance)
instance.accountconfirmed.save()
######################################################
######################################################
class Student(User):
# This is the model class for students
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='students')
matric_number = models.CharField(_('Matriculation number'), max_length=11, blank=False)
department = models.CharField(_('Department'), max_length=40, blank=False)
# has_graduated, level, etc. future possibilities
def __str__(self):
return f'{self.user.email}'
forms.py:
class StudentSignupForm(UserCreationForm):
# first_name = forms.CharField(max_length=70)
# middle_name = forms.CharField(max_length=70, required=False)
# last_name = forms.CharField(max_length=70)
matric_number = forms.CharField(min_length=10, max_length=11, help_text='Your Matric number must be 10 characters')
department = forms.CharField(max_length=40, help_text='e.g Computer Science')
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('matric_number', 'department')
#transaction.atomic
def save(self, commit=True):
# Save the User instance and get a reference to it
user = super().save(commit=False)
user.user_type = User.Types.STUDENT
user.is_active = False
#if commit:
user.save()
print(f' forms.py {user.email} {user.first_name}')
student = Student.objects.create(user=user, matric_number=self.cleaned_data.get('matric_number'), department=self.cleaned_data.get('department'))
# Add other details
# Return User instance, not Student instance
return user
views.py:
class StudentUserSignupView(CreateView):
model = User
template_name = 'account/signup.html'
form_class = StudentSignupForm
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'STUDENT'
return super().get_context_data(**kwargs)
def form_valid(self, form):
user = form.save()
#login(self.request, user)
send_verification_mail(self, user)
return redirect('verification_sent')
Anytime a user signs up, this is what the students table looks like:
Also, this is what the users table look like after signup (with the multiple saves)
So how do I correct the multiple saves in the user table?
Also, How is it even possible to save a model with most of the required fields empty?
As pointed out by #RaghavKundra, the line below was what caused the problem of saving multiple times to the database
class Student(User):
Instead of that, it should be
class Student(models.Model):

How fetch username of staff user in django forms

I am using a custom User model. And I have another Customer model. I want the user field will only show the staff user no other type of user in the field will show in the registration form. In my case, it is showing all types of users whether it is staff or customer or a service user.
Models.py
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=254, unique=True)
name = models.CharField(max_length=254, null=True)
email = models.EmailField(max_length=254, null=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_Customer = models.BooleanField(default=False)
is_Service_Provider = models.BooleanField(default=False)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'username'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def get_absolute_url(self):
return "/users/%i/" % self.pk
def get_username(self):
return self.username
class Customer(models.Model):
user = models.OneToOneField('accounts.User', on_delete=models.SET_NULL, null=True)
email = models.EmailField(max_length=254, null=False)
date_Of_Birth = models.DateField(null=False)
country = models.ForeignKey('accounts.Country', null=True, on_delete=models.SET_NULL, related_name='Country')
state = models.ForeignKey('accounts.State', null=True, on_delete=models.SET_NULL, related_name='State')
city = models.ForeignKey('accounts.City', null=True, on_delete=models.SET_NULL, related_name='city')
address = models.CharField(max_length=254, null=False)
refernce_by_person_name = models.CharField(max_length=254, null=True)
refernce_by_person_contact_no = models.IntegerField(null=True)
phone_no = models.IntegerField(null=False)
alternate_no = models.IntegerField(null=False)
hobbies = models.CharField(max_length=254)
def __str__(self):
return self.user.username
views.py
def form(request):
forms = CustomerRegistrationForm()
if request.method == "POST":
forms = CustomerRegistrationForm(request.POST)
if forms.is_valid():
forms.save()
return redirect('/customer/show')
context = {
'forms' : forms,
}
return render(request,'customer/form.html', context)
forms.py
class CustomerRegistrationForm(forms.ModelForm):
class Meta:
model = Customer
fields = '__all__'
You can filter the staff users in the form like this.
class CustomerRegistrationForm(forms.ModelForm):
user = forms.ModelChoiceField(queryset=User.objects.filter(is_staff=True))
class Meta:
model = Customer
fields = ['user','email','date_of_birth',...]

form object has no attribute 'email' in django

I have a registration form made of 2 forms, from which email field gets saved in both User and Student models. Now, I made an update account info view. Problem is, I want that email will get updated the in both models. But I get error:
'StudentEditForm' object has no attribute 'email'
Here is my code:
class StudentEditForm(forms.ModelForm):
email = forms.EmailField(required=False)
name = forms.CharField(max_length=30)
surname = forms.CharField(max_length=50)
photo = forms.ImageField(required=False)
phone = forms.CharField(max_length=15, required=False)
class Meta:
model = Student
fields = ('email', 'name', 'surname', 'phone', 'photo')
class User(AbstractUser):
pass
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=30, null=True, blank=True, default=None)
surname = models.CharField(max_length=50, null=True, blank=True, default=None)
email = models.EmailField(unique=True, null=True, blank=True, default=None)
student_ID = models.CharField(unique=True, max_length=14,
validators=[RegexValidator(regex='^.{14}$',
message='The ID needs to be 14 characters long.')],
null=True, blank=True, default=None)
photo = models.ImageField(upload_to='students_images', null=True, blank=True, default=None)
phone = models.CharField(max_length=15, null=True, blank=True, default=None)
def __str__(self):
return self.surname
User.student = property(lambda p: Student.objects.get_or_create(user=p)[0])
def profile_edit(request):
user = request.user
student = request.user.student
if request.method != 'POST':
form = StudentEditForm(instance=student)
else:
form = StudentEditForm(request.POST, instance=student)
user.email = form.email
form.save()
return render(request, 'index.html')
context = {
"form": form,
}
return render(request, "registration/profile_edit.html", context)
Again, I need that I will be able to update the email fields. And the email will get saved in User email but also I want it saved to Student email.
call form.is_valid() and then use form.cleaned_data['email'], see https://docs.djangoproject.com/en/1.11/topics/forms/
I had to add
form.is_valid()
and
user.email = form.cleaned_data['email']
but also to add user.save() which solved this issue.

Get email in another model after user is created in django

I am a beginner in django. When admin creates a user, I am trying to save some fields in EmailAddress model.But for some reason the email field is always blank. Is there any way I can update the instance with email in UserProfile or EmailAddress model.
models.py looks like this
User._meta.get_field('email').blank = False
User._meta.get_field('email')._unique = True
class EmailAddress(models.Model):
user = models.OneToOneField(User, unique=True, related_name ='address')
email = models.EmailField()
verified = models.BooleanField(verbose_name=_('verified'), default=True)
primary = models.BooleanField(verbose_name=_('primary'), default=True)
class Meta:
db_table = 'account_emailaddress'
class UserProfile(models.Model, HashedPk):
user = models.OneToOneField(User, unique=True, related_name ='profile')
job_title = models.CharField(max_length=128, blank=True, null=False, default="")
website = models.URLField(max_length=255, blank=True, null=True)
organisation = models.CharField(max_length=50, blank=True, null=True, default="")
phone_number = PhoneNumberField( blank=True, null=True)
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
EmailAddress.objects.create(user=instance)
forms.py looks like this --
class SignUpForm(forms.Form):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
phone_number = PhoneNumberField(label=_("Phone (Please state your country code eg. +44)"))
organisation = forms.CharField(max_length=50)
email = forms.EmailField()
password1 = forms.CharField(max_length=20)
password2 = forms.CharField(max_length=20)
captcha = ReCaptchaField(attrs={'theme' : 'clean'})
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
up = user.profile
up.phone_number = self.cleaned_data['phone_number']
up.organisation = self.cleaned_data['organisation']
user.save()
up.save()
Any help is highly appreciated.
Sorted. It needs to be
EmailAddress.objects.create(user=instance, email=instance.email)

Categories