Django: User information split between "User" and "Person" models - python

Whenever I create a new account, the information I enter "first_name", "last_name", "username", "age", "city", "state", "email" gets split between the built-in User model and the Person model I created. I can see this happening on the admin site, when I click on a user I just created.
Person model:
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length=200, null=True)
first_name = models.CharField(max_length=200, null=True)
last_name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
age = models.CharField(max_length=50, null=True)
View for creating an account:
def create_account(request):
if request.method == 'POST':
new_user = User(username = request.POST["username"],
email=request.POST["email"],
first_name=request.POST["first_name"],
last_name=request.POST["last_name"])
new_user.set_password(request.POST["password"])
new_user.save()
Person.objects.create(user=new_user,
age=str(request.POST.get("age")),
city=str(request.POST.get("city")),
state=str(request.POST.get("state")))
new_user.is_active = True
new_user.save()
return redirect('../')
else:
return render(request, 'polls/create_account.html')
I know the problem is in this model and view, I just can't conceptualize how to put all of the information I submit into the Person model (since the User model only has "first_name", "last_name", "email" attributes).

Since your Person model has a one-to-one with the User, you don't need to store username, first_name, and last_name fields on it. Just leave them on the User model and access them through the relation, you are after all using a relational database.

Related

create django user who can not login

I want to create a user whom I'm using as a ForeignKey and i don't want those users can login to system. I have no idea how to go on. (about setting set_unusable_password() or None, and how to perform it):
my accounts.py file is as
class User(AbstractBaseUser):
GENDER = (("MALE", "Male"), ("FEMALE", "Female"))
user_type = models.CharField(max_length=50, choices=Types.choices, default=Types.PATIENT)
full_name = models.CharField(max_length=255, blank=True, null=True)
phone = models.CharField(max_length=255, unique=True)
email = models.CharField(max_length=255, blank=True, null=True, unique=True)
active = models.BooleanField(default=False)
gender = models.CharField(max_length=15, choices=GENDER)
admin = models.BooleanField(default=False)
staff = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = "phone" # username
REQUIRED_FIELDS = []
objects = UserManager()
thanks in advance guys. <3
you can use the is_active field of the user record
is_active Boolean. Designates whether this user account should be
considered active. We recommend that you set this flag to False
instead of deleting accounts; that way, if your applications have any
foreign keys to users, the foreign keys won’t break.
In View you should also check whether the user is active or not.
For Eg:
def user_login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username = username,password = password)
if user is not None and user.active:
login(request,user)
As you have overide your user model and changed active field from is_active.If active field is False then it will not allow the user to log in if the user is active it will allow user to log in.

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):

Use entered data from another django model

I have two class model, the User and Money Request. I am trying to access the data I entered in the User class so that whenever I requested money using the MoneyRequest class, I can also input my entered email, first and last name together with the withdraw_money.
I really need the data from the User class so that whenever I look at the admin page, I can see the name of the user who sent the money request.
Here is my models.py
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=100, unique=True)
first_name = models.CharField(max_length=100, blank=True, null=True)
last_name = models.CharField(max_length=100, blank=True, null=True)
class MoneyRequest(models.Model):
date_requested = models.DateTimeField(auto_now_add=True)
withdraw_money = models.DecimalField(null=True, blank=True, max_digits=8, decimal_places=2, help_text='Minimum withdrawal is ₱300.00.', validators=[minimum_money])
Here is my views for my MoneyRequest class
class UserAccountsView(CreateView):
model = MoneyRequest
fields = ['withdraw_money',] # Keep listing whatever fields
template_name = 'users/accounts.html'
def form_valid(self, form):
user = form.save()
user.save()
return redirect('users:user_account', self.request.user.username)
What should I put in my MoneyRequest class in order to get the data entered in the User class? Thank you!
In your moneyrequest model add
user = models.ForeignKey(User, on_delete=models.CASCADE)
Then you can get all User model data.

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.

Django: Add additional properties to User

I'm trying to add additional attributes to my "Person" model, namely, "age", "city", and "state." I've been struggling with this for a few days now and have looked up the documentation on how to "Extend the User class" in Django. But, I'm stuck, and when I try to create a new account I get the following error:
TypeError at /polls/signup/add
'age' is an invalid keyword argument for this function
Person model:
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=200, null=True)
last_name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
age = models.CharField(max_length=50, null=True)
Create account view (I'm pretty sure this is where the problem is occurring):
def create_account(request):
if request.method == 'POST':
new_user = User(username = request.POST["username"],
email=request.POST["email"],
first_name=request.POST["first_name"],
last_name=request.POST["last_name"],
age=request.POST["age"],
city=request.POST["city"],
state=request.POST["state"])
new_user.set_password(request.POST["password"])
new_user.save()
Person.objects.create(user=new_user,
first_name=str(request.POST.get("first_name")),
last_name=str(request.POST.get("last_name")),
email=str(request.POST.get("email")),
age=str(request.POST.get("age")),
city=str(request.POST.get("city")),
state=str(request.POST.get("state")))
new_user.is_active = True
new_user.save()
return redirect('../')
else:
return render(request, 'polls/create_account.html')
Any ideas on how I can solve this problem and allow users to add these bonus fields that aren't included with the generic User model?
You should use the Person model instead of User.
if request.method == 'POST':
new_user = User(username = request.POST["username"],
email=request.POST["email"],
first_name=request.POST["first_name"],
last_name=request.POST["last_name"],
)
new_user.set_password(request.POST["password"])
new_user.save()
Person.objects.create(user=new_user,
age=str(request.POST.get("age")),
city=str(request.POST.get("city")),
state=str(request.POST.get("state")))
new_user.is_active = True
new_user.save()
return redirect('../')
else:
return render(request, 'polls/create_account.html')

Categories