I have this method in my views.py file
def guest_login(request):
form = SomeForm(request.POST or None)
if form.is_valid():
email = request.POST['email']
password= request.POST['password']
u = authenticate(username = email, password = password)
if uis not None:
if u.is_active:
login(request, u)
userProfile= request.user.profile
return HttpResponseRedirect(userProfile.get_absolute_url())
else:
messages.error(request, 'Text', extra_tags='text')
else:
messages.error(request, 'Text', extra_tags='text')
else:
form = SomeForm()
context = {
"form": form,
}
return render(request, 'loginpage.html', context)
So, I did not extend the basic User, I created my own, and i did it like this:
class MyUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), max_length=255, db_index=True, blank = False, unique = True)
name= models.CharField(blank = False, max_length = 100)
surname= models.CharField(blank = False, max_length = 100)
# slug = models.SlugField(unique = True)
is_staff = models.BooleanField(
_('some_text'), default=False, help_text=_(
'text'))
is_active = models.BooleanField(_('ctive'), default=True, help_text=_(
'text'
'text'))
date_joined = models.DateTimeField(_('date created'), default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
# abstract = True
def get_full_name(self):
return self.name + " " + self.surname
def get_short_name(self):
return self.name
def get_email(self):
return self.email
def email_user(self, subject, message, from_email=None, **kwargs):
"""Send an email to this User."""
send_mail(subject, message, from_email, [self.email], **kwargs)
class MyUserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse("user:restoraunts", kwargs={"slug": self.slug})
User.profile = property(lambda u: MyUser.objects.get_or_create(user=u)[0])
def create_slug(instance, new_slug=None):
slug = slugify(instance.user.name)
if new_slug is not None:
slug = new_slug
qs = MyUserProfile.objects.filter(slug=slug).order_by('-id')
exists = qs.exists()
if exists:
new_slug = "%s-%s" % (slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_guest_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
#
pre_save.connect(pre_save_guest_receiver, sender=MyUserProfile)
And in settings.py a added:
AUTH_USER_MODEL = 'korisnik.Korisnik'
AUTH_PROFILE_MODULE = 'korisnik.KorisnikProfil'
Everything works fine, except this line:
userProfile= request.user.profile
It says that "MyUser has no attribute profile".
I tried everything, get_profile(), get_profile, profile(), profile... Nothing worked. Can anyone help me? Thank you.
Note that the AUTH_PROFILE_MODULE setting and the get_profile() method where remove in django 1.7.
Try adding a related_name to your MyUserProfile.user field.
Also note that you might be able to just add that slug filed on the user model and avoid the extra relation.
Related
I've created a custom user model, subclassing AbstractUser.
I have a registration view, template, and a CustomUserCreationForm that seems to work fine, and can register users no problem via the front end.
My issue is getting the user logged in. I can't seem to pass the form validation to authenticate them with. I'm always returned with a None user object
With this line for example, I always get None, this failing verification
user = authenticate(request, email=email, password=password)
# user = User.objects.get(email=email, password=hashed_pass)
# Check if authentication successful
if user is not None:
login(request, user)
return HttpResponseRedirect(reverse("clientcare:portal/dashboard"))
else:
return render(request, "clientcare/login.html", {
"message": "Invalid email and/or password.",
'login_form':LoginForm,
})
Forms
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ('email', 'first_name','last_name' ,'city', 'province','age','gender','phone_number','password1', 'password2',)
class LoginForm(forms.Form):
email = forms.EmailField(max_length=100)
password = forms.CharField(widget = forms.PasswordInput())
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = ('email', 'first_name','last_name' ,'city', 'province','age','gender','phone_number',)
Models
# Create your models here.
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError('Users require an email field')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_patient', False)
extra_fields.setdefault('is_provider', True)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self._create_user(email, password, **extra_fields)
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
image_height = models.PositiveIntegerField(null=True, blank=True, editable=False, default="200")
image_width = models.PositiveIntegerField(null=True, blank=True, editable=False, default="200")
date_joined = models.DateTimeField(auto_now=True, null=False, blank=False)
city = models.CharField(null=False, blank=False, max_length=20)
province = models.CharField(null=False, blank=False, max_length=20)
profile_image_url = models.ImageField(null=True, blank=True, upload_to='images/', editable=True)
paid = models.BooleanField(default=False)
phone_number = PhoneField(blank=True, null=True, help_text='Contact phone number', E164_only=False)
in_trial = models.BooleanField(default=True)
recently_active = models.BooleanField(default=True)
gender = models.CharField(choices=(("Male", "Male"),("Female", "Female"), ("Other", "Other")), max_length=6, default="Male", null=False, blank=False)
age = models.SmallIntegerField(max_length=3,null=False, blank=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name',]
# classify if the user is a provider or a patient
is_patient = models.BooleanField('Patient status',default=False)
is_provider = models.BooleanField('Provider status',default=False)
def __str__(self):
return f"{self.get_full_name()}"
Login View
def login_view(request):
if request.method == "POST":
login_form = LoginForm(data=request.POST)
if login_form.is_valid():
email = login_form.cleaned_data['email']
password = login_form.cleaned_data['password']
# hashed_pass = bcrypt.hashpw(raw_pass, salt)
# if bcrypt.checkpw(raw_pass, hashed_pass):
user = authenticate(request, email=email, password=password)
# user = User.objects.get(email=email, password=hashed_pass)
# Check if authentication successful
if user is not None:
login(request, user)
return HttpResponseRedirect(reverse("clientcare:portal/dashboard"))
else:
return render(request, "clientcare/login.html", {
"message": "Invalid email and/or password.",
'login_form':LoginForm,
})
else:
return render(request, "clientcare/login.html", {
"message": "Invalid login data. Please try again",
'login_form':LoginForm,
})
else:
return render(request, "clientcare/login.html", {
'login_form':LoginForm,
})
Registration view
def register(request):
# Adding the salt to password
if request.method == "POST":
register_form = CustomUserCreationForm(request.POST)
if register_form.is_valid():
email = register_form.cleaned_data['email']
city = register_form.cleaned_data["city"]
province = register_form.cleaned_data["province"]
first_name = register_form.cleaned_data["first_name"]
last_name = register_form.cleaned_data["last_name"]
phone_number = register_form.cleaned_data["phone_number"]
age = register_form.cleaned_data["age"]
gender = register_form.cleaned_data["gender"]
# Ensure password matches confirmation
password = register_form.cleaned_data["password1"]
confirmation = register_form.cleaned_data["password2"]
if password != confirmation:
return render(request, "clientcare/register.html", {
"messsage": "Passwords must match."
})
# Hashing the password
# hashed = bcrypt.hashpw(password, salt)
# password = hashed
# Attempt to create new user
try:
user = User.objects.create(email=email, city=city, province=province, password=password, first_name=first_name, last_name=last_name, phone_number=phone_number, age=age, gender=gender)
user.save()
except IntegrityError:
return render(request, "clientcare/register.html", {
"message": "ERROR. TRY AGAIN",
})
login(request, user)
return HttpResponseRedirect(reverse("clientcare:index"))
else:
return render(request, "clientcare/register.html", {
"message": "ERROR. PLEASE CONFIRM REGISTRATION INFO",
})
else:
return render(request, "clientcare/register.html",{
'registration_form':CustomUserCreationForm
})
I have my user in settings.py as such:
AUTH_USER_MODEL = 'clientcare.User'
I'm well aware I can use AllAuth or other auth libraries. But I'm trying to understand things on a lower level before using such libraries.
Any help would be appreciated.
Nothing I try seems to work in getting my custom user model logged in. Do I need to write a custom backend? AuthenticationForm doesn't seem to work just as my own login form doesn't seem to validate
HOWEVER, if I update a users password via the admin(with superuser), then the user can login no problem with the updated password.. so my CustomUserChangeForm does the job. What am I missing?
I'm putting a model of my old project here as an example. Here I used the user model as it is and added the fields I wanted to add to the new class that user is also a field there. Django's auth module works as is and no additional coding was required.
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import ugettext_lazy as _
from backend.custom_fields import AutoOneToOneField
from backend import definitions
from django.urls import reverse
from django.db.models.signals import post_save
from django.dispatch import receiver
from backend.convert import convert_string_to_url_safe
from random import randint
from backend.image_operation import image_resize, image_convert_to_jpg
EMAIL_PRIVACY_CHOICES = (
(0, _('Display your e-mail address.')),
(1, _('Hide your e-mail address but allow form e-mail.')),
(2, _('Hide your e-mail address and disallow form e-mail.')),
)
PHONE_PRIVACY_CHOICES = (
(0, _('Display your phone no.')),
(1, _('Hide your phone no.')),
)
def avatar_upload_file_name_path(instance, filename_ext):
ext = filename_ext.split('.')[-1]
return f'profile_uploads/{convert_string_to_url_safe(instance.get_full_name)}-{randint(1000, 10000)}.{ext}'
def photo_upload_file_name_path(instance, filename_ext):
ext = filename_ext.split('.')[-1]
return f'profile_uploads/{convert_string_to_url_safe(instance.get_full_name)}-{randint(1000, 10000)}.{ext}'
def resized_photo_upload_file_name_path(instance, filename_ext):
ext = filename_ext.split('.')[-1]
return f'profile_uploads/resized-{convert_string_to_url_safe(instance.get_full_name)}-{randint(1000, 10000)}.{ext}'
class PlatformUser(models.Model):
user = AutoOneToOneField(User, on_delete=models.CASCADE)
slug = models.CharField(max_length=100, null=True, blank=True)
title = models.CharField(max_length=60, blank=True, default='')
description = models.TextField(blank=True, default='')
phone = models.CharField(max_length=25, blank=True, default='')
facebook_address = models.URLField(blank=True, default='')
twitter_address = models.URLField(blank=True, default='')
instagram_address = models.URLField(blank=True, default='')
linkedin_address = models.URLField(blank=True, default='')
youtube_address = models.URLField(blank=True, default='')
site = models.URLField(_('Personal Site'), blank=True)
skype_name = models.CharField(_('Skype Name'), max_length=100, blank=True, default='')
birth_date = models.DateTimeField(_('Birth Date'), blank=True, null=True)
location = models.CharField(_('Location'), max_length=30, blank=True)
photo = models.ImageField(upload_to=photo_upload_file_name_path, blank=True, default='')
photo_resized = models.ImageField(upload_to=resized_photo_upload_file_name_path, blank=True, null=True)
show_photo = models.BooleanField(_('Show avatar'), blank=True, default=True)
show_signatures = models.BooleanField(_('Show signatures'), blank=True, default=True)
show_smilies = models.BooleanField(_('Show smilies'), blank=True, default=True)
email_privacy_permission = models.IntegerField(_('Privacy permission'), choices=EMAIL_PRIVACY_CHOICES, default=1)
phone_privacy_permission = models.IntegerField(_('Privacy permission'), choices=PHONE_PRIVACY_CHOICES, default=1)
auto_subscribe = models.BooleanField(_('Auto subscribe'),
help_text=_("Auto subscribe all topics you have created or reply."),
blank=True, default=False)
post_count = models.IntegerField(_('Post count'), blank=True, default=0)
likes_count = models.IntegerField(default=0)
view_count = models.IntegerField(default=0)
signature = models.TextField(_('Sign'), blank=True, default='', max_length=definitions.SIGNATURE_MAX_LENGTH)
signature_html = models.TextField(_('Sign as HTML'), blank=True, default='',
max_length=definitions.SIGNATURE_MAX_LENGTH)
verification_code = models.CharField(_('Verify Code'), blank=True, default='', max_length=40)
created = models.DateTimeField(_('Created'), auto_now_add=True)
updated = models.DateTimeField(_('Updated'), auto_now=True, null=True)
class Meta:
ordering = ['user']
get_latest_by = 'created'
verbose_name = _('Platform Member')
verbose_name_plural = _('Platform Members')
def __init__(self, *args, **kwargs):
super(PlatformUser, self).__init__(*args, **kwargs)
self.__original_image_filename = self.photo.name
#property
def email(self):
return self.user.email
#property
def get_full_name(self):
full_name = str(self.user.first_name.title())
if len(full_name) > 0:
full_name += " "
full_name += str(self.user.last_name.title())
if len(full_name) == 0:
full_name = self.user.username
return full_name
#property
def username(self):
return self.user.username
#property
def first_name(self):
return self.user.first_name
#property
def last_name(self):
return self.user.last_name
def __str__(self):
return f"[{self.user.first_name} {self.user.last_name}] - ({self.user.email})"
def get_absolute_url(self):
return reverse('profile',
args=[str(self.get_slug())])
def get_slug(self):
if not self.slug:
self.slug = self.user.username
return self.slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_slug()
if self.photo and (self.photo.name != self.__original_image_filename or not self.photo_resized):
self.photo_resized = image_resize(400, 400, self.photo)
self.photo = image_convert_to_jpg(self.photo)
super(PlatformUser, self).save(*args, **kwargs)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
PlatformUser.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
platform_users = PlatformUser.objects.filter(user=instance)
if len(platform_users) > 0:
platform_user = platform_users[0]
else:
platform_user = PlatformUser.objects.create(user=instance)
platform_user.save()
as you could see there are receivers for creating my own platform user row on database when user created.
This way is simple but useful in my opinion. Your way is more correct but more complex.
BTW I dont use and dont like django forms at all.
Solved. I realized I wasn't using the create_user method I wrote in my registration view.
Updated the line below:
user = User.objects.create_user(email=email, city=city, province=province, password=password, first_name=first_name, last_name=last_name, phone_number=phone_number, age=age, gender=gender)
After this, my login form and validation worked. So for anyone having a similar issue, make sure you're using the create_user method if you wrote one/if you're using a custom user model/if you call user.set_password(password) in that method and not in your view.
I am editing profile using Django framework. The problem lies where the user login can see the profile of other user when they change the id in the web address. Could someone help me so that I can only view the user's profile who is login and if they change the id they will receive an error. Thanks
Edit User Profile
#login_required(login_url = 'signin')
#user_passes_test(check_role_super)
def sa_profile_edit(request, user_id=None):
user = get_object_or_404(User, pk=user_id)
user_profile = get_object_or_404(userMember, pk=user_id)
if request.method == 'POST':
form = UserFormAdmin(request.POST or None, instance=user)
form_profile = MemberForm(request.POST or None, instance=user_profile)
else:
form = UserFormAdmin(instance=user)
form_profile = MemberForm(instance=user_profile)
context = {
'form': form,
'user': user,
'form_profile': form_profile,
'user_profile': user_profile
}
return render(request, 'pages/sa_editProfile.html', context)
If role is super
def check_role_super(user):
if user.role == 3:
return True
else:
raise PermissionDenied
Model
class User(AbstractBaseUser):
MEMBER = 1
ADMIN = 2
SUPERADMIN = 3
ROLE_CHOICE = (
(MEMBER, 'Member'),
(ADMIN, 'Admin'),
(SUPERADMIN, 'Super Admin')
)
ACTIVE = 1
DELETED = 2
DEACTIVATED = 3
STATUS = (
(ACTIVE, 'Active'),
(DELETED, 'Deleted'),
(DEACTIVATED, 'Deactivated')
)
first_name = models.CharField(max_length=50)
middle_name = models.CharField(max_length=50, default="Some String")
last_name = models.CharField(max_length=50)
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(max_length=100, unique=True)
mobile_number = models.CharField(max_length = 100, db_index=True, null = True,
validators=[
RegexValidator(
regex='^(\+\d{1,3})?,?\s?\d{8,13}',
message='Phone number must not consist of space and requires country
code. eg : +639171234567',
),
])
password = models.CharField(max_length = 100,validators=[MinLengthValidator(8),
])
role = models.PositiveSmallIntegerField(choices=ROLE_CHOICE, blank=True, null=True)
status = models.PositiveSmallIntegerField(choices=STATUS, blank=True, null=True)
# required fields
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now_add=True)
created_date= models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_superadmin = models.BooleanField(default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'first_name', 'middle_name', 'last_name', 'mobile_number']
objects = UserManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
def get_role(self):
if self.role == 1:
user_role = 'Member'
elif self.role == 2:
user_role = 'Admin'
elif self.role == 3:
user_role = 'Super Admin'
return user_role
def get_status(self):
if self.status == 1:
user_status = 'Active'
elif self.status == 2:
user_status = 'Deleted'
elif self.status == 3:
user_status = 'Deactivated'
return user_status
class userMember(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
birthdate = models.DateField(blank=True, null=True)
profile_picture = models.ImageField(upload_to='users/profile_pictures', blank=True, null=True)
cover_color = ColorField(format='hexa', blank=True, null=True)
upload_id = models.ImageField(upload_to='member/id', blank=True, null=True)
created_at = models.DateTimeField(auto_now=True)
modified_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
You can get the current user from the request instead, replace user = get_object_or_404(User, pk=user_id) with:
user = request.user
if not user.is_authenticated:
raise Http404()
========= view.py ===========
# User Profile Update
def ProfileView(request):
if request.user.is_authenticated:
form =UserProfileChangeForm(instance=request.user)
context = {'form':form}
if request.method == 'POST':
form =UserProfileChangeForm(request.POST,instance=request.user)
if form.is_valid():
form.save()
messages.info(request,'Profile Successfully Updated')
return redirect('/profile/')
else:
form =UserProfileChangeForm(instance=request.user)
user_data = request.user
context = {'form':form,'user_data':user_data}
return rend
er(request,'profile.html',context)
======= form.py ========
from django.contrib.auth.forms import UserChangeForm
# User Profile
class UserProfileChangeForm(UserChangeForm):
password =None
class Meta:
model = User
fields = ['username','first_name','last_name','email']
widgets = {
'username':forms.TextInput(attrs={'class':'form-control','placeholder':'Enter Username'}),
'first_name':forms.TextInput(attrs={'class':'form-control','placeholder':'Enter First Name'}),
'last_name':forms.TextInput(attrs={'class':'form-control','placeholder':'Enter Last Name'}),
'email':forms.TextInput(attrs={'class':'form-control','placeholder':'Enter E-Mail'}),
}
you should implement class with UUID concept. UUID meant to protect url address.
but as short and not ideal solution
you can overwrite id in your code by request.user.id
lets say logged in user has id=3 and he tries to change it to id=4 and then view function will get called. but you can overwrite that id by as i said above and he ll end up seeing his profile anyways. but URL WILL display wrong id so this is not a good option.
When I send request in Postman like this:
it returns me all fields fine expect the profile_photo. profile_photo in response is null and I don't know what is the problem. It should be the new uuid photo name.
Here is my model:
class User(AbstractBaseUser, PermissionsMixin):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
city = models.CharField(max_length=150, blank=True)
description = models.CharField(max_length=1000, blank=True)
profile_photo = models.CharField(max_length=500, blank=True)
date_joined = models.DateTimeField(default=timezone.now)
about = models.TextField(_(
'about'), max_length=500, blank=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomAccountManager()
object = models.Manager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'city']
def __str__(self):
return self.email
This is my view:
class CustomUserUpdate(generics.UpdateAPIView):
permission_classes = [IsAuthenticated]
queryset = User.objects.all()
serializer_class = UserUpdateSerializer
def get_object(self):
return self.request.user
This is my serializer. Here i am setting the new photo name. When I print the new name here like this: print(instance.profile_photo) it shows me the new file name fine. But in the response i get null.
class UserUpdateSerializer(serializers.ModelSerializer):
profile_photo = serializers.FileField(required=False)
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo')
def __init__(self, *args, **kwargs):
super(UserUpdateSerializer, self).__init__(*args, **kwargs)
self.fields['email'].required = False
self.fields['description'].required = False
def update(self, instance, validated_data):
if instance.id == self.context['request'].user.id:
instance.email = validated_data.get('email', instance.email)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.city = validated_data.get('city', instance.city)
instance.description = validated_data.get('description', instance.description)
uploaded_file = validated_data.get('profile_photo', None)
if uploaded_file:
validate_extension(uploaded_file.name)
instance.profile_photo = handle_uploaded_file(uploaded_file)
instance.save()
return instance
def handle_uploaded_file(file):
extension = os.path.splitext(file.name)[1]
new_filename = f"{uuid.uuid4()}{extension}"
destination = open(f'static/user/images/{new_filename}', 'wb+')
for chunk in file.chunks():
destination.write(chunk)
destination.close()
return new_filename
def validate_extension(filename):
extension = os.path.splitext(filename)[1].replace(".", "")
if extension.lower() not in ALLOWED_IMAGE_EXTENSIONS:
raise serializers.ValidationError(
(f'Invalid uploaded file type: {filename}'),
code='invalid',
)
While sending requests you are passing file as input to the serializer. Serializer validates it and saves it. Till here it is perfectly fine.
Now while returning the response it expects a file from instance.profile_photo but to the serializer validator's surprise, it contains a string value (i.e UUID file name). The problem is here!
We got the bug point. Let's solve it.
To solve it, differentiate the names for the request(File) and response (File name i.e UUID string):
class UserUpdateSerializer(serializers.ModelSerializer):
profile_image = serializers.FileField(required=False, write_only=True)
profile_photo = serializers.ReadOnlyField()
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo', 'profile_image')
def __init__(self, *args, **kwargs):
super(UserUpdateSerializer, self).__init__(*args, **kwargs)
self.fields['email'].required = False
self.fields['description'].required = False
def update(self, instance, validated_data):
if instance.id == self.context['request'].user.id:
instance.email = validated_data.get('email', instance.email)
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.city = validated_data.get('city', instance.city)
instance.description = validated_data.get('description', instance.description)
uploaded_file = validated_data.get('profile_image', None)
if uploaded_file:
validate_extension(uploaded_file.name)
instance.profile_photo = handle_uploaded_file(uploaded_file)
instance.save()
return instance
We have solved the bug!
I created MainUser model and this model has unicode method, but here I have problem like 'unicode' object is not callable
this my authorization function:
def auth(request):
params = dict()
if request.method == 'POST':
try:
login = request.POST['login']
password = request.POST['password']
except:
messages.add_message(request, messages.WARNING, 'empty fields')
return redirect(reverse('main:sing_in'))
user = authenticate(username=login, password=password)
if user is not None:
login(request, user)
return redirect('main:work')
else:
return redirect(reverse('main:sing_in'))
return render(request, 'sing_in.html', params)
and this one my mainuser model:
class MainUser(AbstractBaseUser, PermissionsMixin):
"""
django user model
"""
login = models.CharField(max_length=20, blank=False, unique=True,
db_index=True, verbose_name=u'Логин')
first_name = models.CharField(max_length=222, blank=True,
verbose_name=u'Имя')
second_name = models.CharField(max_length=222, blank=True,
verbose_name=u'Фамилия')
email = models.EmailField(max_length=100, blank=True, verbose_name=u'email')
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MainUserManager()
USERNAME_FIELD = 'login'
REQUIRED_FIELDS = []
def full(self):
return {
"first_name": self.first_name,
"second_name": self.second_name,
"email": self.email
}
#property
def is_staff(self):
return self.is_admin
def get_short_name(self):
return self.login
def get_full_name(self):
return u"{0} {1}".format(self.second_name, self.first_name)
def __unicode__(self):
return u"{}".format(self.login)
class Meta:
verbose_name = u"Пользователь"
verbose_name_plural = u"Пользователи"
I can't understand where bug in the code, it give error when i call login(request, user)
You've redefined login to be the variable that stores the data from your field. Call it something else.
I presume I have missed something silly, but I can't make the inlineformset to work with me. I have a very similar code in my site, which works fine. The original code was for registration and I have tried to modify it so user-data could be updated/changed.
models.py
class Profiles(AbstractBaseUser):
activation_key = Utils().activationKey()
email = models.EmailField(verbose_name = 'email address', max_length = 255, unique = True)
activation_code = models.CharField(max_length=40, default=activation_key)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = ProfilesManager()
USERNAME_FIELD = 'email'
def get_email(self):
return self.email
def get_full_name(self):
# The user is identified by their email address
userdata = ProfileData.objects.get(uid_id=self.id)
return userdata.full_name
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
def __unicode__(self):
return u'%d' % self.id
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
class ProfileData(models.Model):
profile = models.ForeignKey(Profiles)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
full_name = models.CharField(max_length=100)
image = models.ImageField(upload_to='media/user/avatar', blank=True, null=True)
def get_first_name(self):
return self.first_name
def get_last_name(self):
return self.last_name
def get_full_name(self):
return self.full_name
def get_avatar(self):
return self.image
def save(self, *args, **kwargs):
self.full_name = '{0} {1}'.format(self.first_name, self.last_name)
super(ProfileData, self).save(*args, **kwargs)
views.py
class ProfileView(TemplateView):
template_name = 'profiles/profile.html'
form = ProfileDataForm
formset = ProfileFormset
def get(self, request, user_id):
profile = ProfileData.objects.select_related('Profiles').filter(profile=user_id).first()
if request.user.id and user_id:
if int(request.user.id) is int(user_id):
instance = ProfileData.objects.filter(profile=request.user).first()
return render(request, self.template_name, {'form': self.form(instance=request.user), 'formset': self.formset(), 'profile': profile})
else:
return render(request, self.template_name, {'profile': profile})
#method_decorator(sensitive_post_parameters())
#method_decorator(csrf_protect)
#method_decorator(never_cache)
#method_decorator(api_view(['POST']))
#transaction.non_atomic_requests
def post(self, request, user_id):
form = self.form(request.POST, instance=request.user)
if form.is_valid():
if form.data['password'] == form.data['conf_password']:
transaction.set_autocommit(False)
try:
profile = form.save(commit=False)
profile_formset = self.formset(request.POST, request.FILES, instance=profile)
if profile_formset.is_valid():
print 'formset is valid...'
profile.save()
profile_formset.save()
finally:
transaction.set_autocommit(True)
else:
print 'Passwords doesn\'t match'
else:
print 'Form is not valid...'
user = ProfileData.objects.select_related().filter(profile=user_id).first()
return HttpResponseRedirect('/user/{0}/'.format(user_id))
forms.py
class ProfileDataForm(forms.ModelForm):
email = forms.CharField(max_length=100, label='', widget=forms.TextInput(attrs={'placeholder': 'E-mail', 'class': 'form-control'}), required=False)
password = forms.CharField(max_length=100, label='', widget=forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}), required=False)
conf_password = forms.CharField(max_length=100, label='', widget=forms.PasswordInput(attrs={'placeholder': 'Confirm Password', 'class': 'form-control'}), required=False)
class Meta:
model = Profiles
fields = ['email', 'password', 'conf_password']
exclude = ('full_name', 'image', )
def clean_password2(self):
# Check that the two password entries match
password = self.cleaned_data.get('password')
conf_password = self.cleaned_data.get('conf_password')
if password and conf_password and password != conf_password:
raise forms.ValidationError('Passwords don\'t match')
return conf_password
def save(self, commit=True):
print 'saving form...'
# Save the provided password in hashed format
user = super(ProfileDataForm, self).save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user
ProfileFormset = inlineformset_factory(Profiles, ProfileData,
exclude=('full_name', ),
can_delete=False,
extra=1,
widgets={
'first_name': forms.TextInput(attrs={'placeholder': 'First name', 'class': 'form-control'}),
'last_name': forms.TextInput(attrs={'placeholder': 'Last name', 'class': 'form-control'}),
},
labels={
'first_name': None,
'last_name': None
},
)
I have made sure to include everything, there is no error, the debug doesn't pop up and form is saved (views->ProfilesViews->post).
Despite everything, the inlineform doesn't save. I have tried to make a custom def save(), without success.
the variable "form" in views is connected to Profiles while "profile_formset" is connected to ProfileData.
I am usually rubbish at asking questions here, I shall edit if you find me unclear.
Although this is not a solution, There are a few things to note here:
1) I didn't understand why you are using exclude after selecting the fields.
2) You are doing password matching twice in forms.py and views.py
3) In forms.py the method that validates field, as far as I know should be like clean_fieldname.
Please correct me if I'm wrong.