I want to use hashing field set_password from User model in django.contrib.auth.models and I'm currently using a custom User model for that.
I'm getting the following error: Attribute error: 'User' object has no attribute 'set_password'
models.py
from django.db import models
class User(models.Model):
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
profile_picture =
models.ImageField(upload_to="user_data/profile_picture", blank=True)
username = models.CharField(max_length=100)
birth_date = models.DateField(blank=True)
gender = models.CharField(max_length=10, blank=True)
password = models.CharField(max_length=1000)
contact = models.CharField(max_length=10, blank=True)
email = models.CharField(max_length=100)
time_stamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.username
views.py
...
from .models import User
...
def post(self, request):
# Data is here
form = self.form_class(request.POST)
if form.is_valid():
# create object of form
user = form.save(commit=False)
# cleaned/normalised data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# convert plain password into hashed
user.set_password(user.password)
user.save()
return HttpResponse('Done here.')
...
forms.py (just used a widget in forms.py)
from .models import User
from django import forms
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'password']
This is a really easy fix. Just change your models.py file like so:
from django.contrib.auth.models import AbstractBaseUser
class User(AbstractBaseUser):
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
profile_picture = models.ImageField(upload_to="user_data/profile_picture", blank=True)
username = models.CharField(max_length=100)
birth_date = models.DateField(blank=True)
gender = models.CharField(max_length=10, blank=True)
password = models.CharField(max_length=1000)
contact = models.CharField(max_length=10, blank=True)
email = models.CharField(max_length=100)
time_stamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.username
That way, your user model will inherit all of the AbstractBaseUser methods, including set_password.
Look at this full example from the documentation for extra information.
Related
I am trying to return extra data for the "following_user" but I'm getting returned the data for the "user" instance
The View to get Users following list:
class UsersFollowing(generics.ListAPIView):
authentication_class = [authentication.TokenAuthentication]
permission_class = [permissions.IsAuthenticated]
serializer_class = FollowingSerializer
def get_queryset(self):
user = self.request.GET.get('user_id')
obj = Follow.objects.filter(user=user)
return obj
the Serializer:
class FollowingSerializer(serializers.ModelSerializer):
avi_pic = serializers.SerializerMethodField('get_avi_pic')
username = serializers.SerializerMethodField('get_username')
first_name = serializers.SerializerMethodField('get_first_name')
last_name = serializers.SerializerMethodField('get_last_name')
def get_username(self, obj):
username = obj.following_user.username
return username
def get_first_name(self, obj):
first_name = obj.following_user.first_name
return first_name
def get_last_name(self, obj):
last_name = obj.following_user.last_name
return last_name
class Meta:
model = Follow
fields = "__all__"
my Follow model:
class Follow(models.Model):
user = models.ForeignKey(
"User", related_name="follower", on_delete=models.CASCADE)
following_user = models.ForeignKey(
"User", related_name="following", blank=True, on_delete=models.CASCADE)
date_followed = models.DateTimeField(auto_now_add=True)
My User model:
class User(AbstractUser):
objects = UserManager()
avi_pic = models.ImageField(
_('avi_pic'), upload_to=aviFile, null=True, blank=True)
email = models.EmailField(max_length=250, unique=True)
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
username = models.CharField(max_length=60, unique=True)
I think your naming of foreign key fields is not good. It is often better not to add the trailing the word id. Then the Django ORM will automatically adds the field named user_id.
class Follow(models.Model):
user = models.ForeignKey(
"User", related_name="follower", on_delete=models.CASCADE)
following_user = models.ForeignKey(
"User", related_name="following", blank=True, on_delete=models.CASCADE)
date_followed = models.DateTimeField(auto_now_add=True)
And then in the serializer, you could set the serializer of the User model.
class FollowingSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only = True)
following_user = UserSerializer(read_only = True)
class Meta:
model = Follow
fields = "__all__"
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):
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',...]
I'm learning django and in one of my challenges I want to add 3 foreign keys to the sign up form django-all-auth, but I have the error: NOT NULL constraint failed: advertising_profile.user_id
please can you help me and explain what Im failing.
I am trying to save this information for the registration form
==========views.py==================
def register(request):
form = CustomSignUpProfileModelForm()
if request.method == "POST":
form = CustomSignUpProfileModelForm(data=request.POST)
if form.is_valid():
#user = form['customSignUp'].save(commit=False)
profile = form.save(commit=False)
profile.user = request.user
profile.save()
#user = form.save()
if profile is not None:
do_login(request, user)
return redirect('welcome')
#form.fields['username'].help_text = None
#form.fields['password1'].help_text = None
#form.fields['password2'].help_text = None
return render(request,"account/signup.html",{'form':form})
==========end views.py======================
=========forms.py======================
from django import forms
from django.forms import ModelForm
from betterforms.multiform import MultiModelForm
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth.models import User
from .models import Profile, Region, Commune, Nation
class CustomSignUp(UserCreationForm):
username = forms.EmailField(label="Correo electrónico")
class Meta:
model = User
fields = ["username","password1","password2"]
class CustomSignIn(AuthenticationForm):
username = forms.EmailField(label="Correo Electrónico")
class Meta:
model = User
fields = ["username","password"]
class Profile(forms.ModelForm):
class Meta:
model = Profile
fields = ["name","last_name","mother_last_name","phone","region","commune","nation"]
class Region(forms.ModelForm):
class Meta:
model = Region
fields = ["name"]
class Commune(forms.ModelForm):
class Meta:
model = Commune
fields = ["name"]
class Nation(forms.ModelForm):
class Meta:
model = Nation
fields = ["name"]
class CustomSignUpProfileModelForm(MultiModelForm):
form_classes = {
'customSignUp': CustomSignUp,
'profile':Profile,
}
=============end forms.py =====================
============== models.py =====================
from django.db import models
from django.contrib.auth.models import User
from phone_field import PhoneField
# Create your models here.
class Region(models.Model):
cprovin = models.CharField(max_length=4)
name = models.CharField(max_length=50,verbose_name="Región")
def __str__(self):
return self.name
class Commune(models.Model):
cpoblac = models.CharField(max_length=4)
name = models.CharField(max_length=50, verbose_name="Comuna")
region = models.ForeignKey(Region,on_delete=models.CASCADE, verbose_name="Elija una región",null=False, blank=False)
def __str__(self):
return self.name
class Nation(models.Model):
name = models.CharField(max_length=50, verbose_name="Nacionalidad", null=False, blank=False)
def __str__(self):
return self.name
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,null=False, blank=False)
name = models.CharField(max_length=30, verbose_name="Nombre", null=False, blank=False)
last_name = models.CharField(max_length=30, verbose_name="Apellido Paterno", null=False, blank=False)
mother_last_name = models.CharField(max_length=30, verbose_name="Apellido Materno", null=False, blank=False)
nation = models.ForeignKey(Nation,on_delete=models.CASCADE, verbose_name="Elija su nacionalidad", null=False, blank=False)
region = models.ForeignKey(Region,on_delete=models.CASCADE,verbose_name="Elija una región", null=False, blank=False)
commune = models.ForeignKey(Commune,on_delete=models.CASCADE,verbose_name="Elija una comuna", null=False, blank=False)
phone = PhoneField(null=False, blank=False, unique=True, help_text="Número de contacto")
def __str__(self):
return self.name
============== end models.py =====================
in this line profile.user = request.user but you should confirm that your model should have user
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)