Django login/register issue - python-3.x

I am new to Django and am building a database-driven website using PyCharm.
I am having an issue with users registering/logging in. What is happening is, when a user registers, I check the "Database" tab to the right, and the information will be passed into a table named "SavBlock_user", which will have the users name, password, etc.. Then, when I try to log in, it won't allow me to login due to incorrect username/password. However, if I try to login using a username/password from a different table named "auth_user" (like username: admin / password: admin), then I can successfully login. I'm not sure how to fix this.
Ideally, what I would like to do is completely remove the "SavBlock_user" table and strictly use "auth_user" for all of my users, but I'm not sure how to do this. I may have created a 'custom' user model back when I was learning the system, but I can't remember.
My files:
Project\register\forms.py
from django import forms
from SavBlock.models import * # <--- Contains User
''' Form for users to register '''
class RegisterForm(forms.ModelForm):
email = forms.EmailField(
initial='myemail#savagez.com'
)
uso_validate = forms.BooleanField(
label='Are you a PSMC member? (Chief, Uso, Anak)',
initial=False
)
class Meta:
model = User
widgets = {
'password': forms.PasswordInput(),
}
fields = '__all__'
Project\register\views.py
from django.http import request
from django.shortcuts import render, redirect
from .forms import RegisterForm
# Create your views here.
def register(response):
if response.method == "POST":
form = RegisterForm(response.POST or None)
if form.is_valid():
form.save()
return redirect('/dashboard/')
else:
form = RegisterForm()
return render(response, 'register/register.html', {'form': form})
Project\SavBlock\models.py
from django.db import models
class User(models.Model):
username = models.CharField("user name", max_length=50, default='')
email = models.EmailField("email address", unique=True, default='DEFAULT VALUE')
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
password = models.CharField("password", unique=True, max_length=50, default='')
rank = {
0: 'Supporter',
1: 'Anak',
2: 'Uso',
3: 'Chief'
}
#TODO: FIT __INIT__
'''
def __init__(self, first_name, last_name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.first_name = first_name.title()
self.last_name = last_name.title()
'''
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
class Uso(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[2]
----EDIT----
I fixed the different user tables and basically reset the migrations. Now, all users are showing up under a single user table SavBlock_user. However, the login issue is still there.
Admin was created using the terminal manage.py createsuperuser command. I am able to login on the webpage using this account.
testing123 was created using the registration form. It pulls up a message that says "Please enter a correct username and password".
Anyone have any ideas?

Related

Field 'id' expected a number but got <User: ben>

I created a population script for a django website however, after running the script and making migrations, I logged in to the django admin page for my site to access the objects created using the script and could not do it for my Business model. It works fine for my other models.
I get this error when I try to access the registered Businesses in my database from the Django admin page. It does not seem to trace back to any of my code but rather to a template in the admin folder of my python environment. Here's the error message:
error message
Here are my models:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to="profile_images", blank=True, default="profile_images/default.png")
description = models.TextField(max_length=1024, default="")
# boolean flag for identifying business owners
is_business_owner = models.BooleanField(default=False)
def __str__(self):
return self.user.username
class Business(models.Model):
owner_fk = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=128)
address = models.CharField(max_length=128)
img = models.ImageField(upload_to="business_images", blank=True)
slug = models.SlugField(unique=True)
class Meta:
verbose_name_plural = 'Businesses'
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Business, self).save(*args, **kwargs)
def __str__(self):
return f"{self.name} owned by {UserProfile.objects.get(pk=self.owner_fk).username}"
Here is how I created the objects through the population script:
def add_user(username, firstname, lastname, password, profile_pic, description,
is_business_owner):
new_user = User.objects.get_or_create(username=username, password=password,
first_name=firstname, last_name=lastname)
if new_user[1]:
new_profile = UserProfile(user=User.objects.get(username=username))
new_profile.profile_pic = profile_pic
new_profile.description = description
new_profile.is_business_owner = is_business_owner
new_profile.save()
def add_business(owner, name, address, img):
new_business = Business(name=name, owner_fk=User.objects.get(username=owner))
new_business.address = address
new_business.img = img
new_business.save()
Any help would be appreciated, thanks.
Your Business class has got __str__ method. You are trying to pass User object to pk (id) key.
class Business(models.Model):
def __str__(self):
return f"{self.name} owned by {UserProfile.objects.get(pk=self.owner_fk).username}"
Instead of searching User object in database Change it to:
return f"{self.name} owned by {self.owner_fk.username}"
because you don't have to search database for related object, just address it directly.

using custom model fo django djoser

i am creating api endpoints for user management using Djoser and i want to use a custom model to create user and login i only want to use email.
the user entity given to me does not have a username field
below i will share the various settings i have set up for my apps
#accounts/model.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class CustomUser(AbstractUser):
username = None
email = models.EmailField(unique=True)
REQUIRED_FIELDS = ['first_name', 'last_name']
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
My serializer file
#accounts/serializers.py
from djoser.serializers import UserCreateSerializer, UserSerializer
from rest_framework import serializers
from rest_framework.fields import CurrentUserDefault
from .models import CustomUser
class UserCreateSerializer(UserCreateSerializer):
class Meta:
model = CustomUser
fields = ['id', 'email', 'first_name', 'last_name']
#settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSIONS_CLASSES': (
'rest_framework.permissions.IsAuthenticated'
)
}
AUTH_USER_MODEL = 'accounts.CustomUser'
DJOSER = {
'LOGIN_FIELD': 'email',
'USER_CREATE_PASSWORD_RETYPE': True,
'SERIALIZERS': {
'user_create': 'accounts.serializers.UserCreateSerializer',
'user': 'accounts.serializers.UserCreateSerializer',
# 'current_user': 'accounts.serializers.CurrentUserSerializer'
}
when i try to register user i get
TypeError at /auth/users/
create_user() missing 1 required positional argument: 'username'
Request Method: POST
Request URL: http://127.0.0.1:8000/auth/users/
Django Version: 3.1
Exception Type: TypeError
Exception Value:
create_user() missing 1 required positional argument: 'username'
Exception Location: /home/femiir/.virtualenvs/codegarage/lib/python3.8/site-packages/djoser/serializers.py, line 73, in perform_create
Python Executable: /home/femiir/.virtualenvs/codegarage/bin/python
Python Version: 3.8.5
please what i my doing wrong ?
You need to have a custom user manager, probably something like this:
from django.contrib.auth.base_user import BaseUserManager
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email, first name,
last name and password.
"""
if not email:
raise ValueError("Users must have an email address")
user = self.model(
email=self.normalize_email(email),
**extra_fields,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
"""
Creates and saves a superuser with the given email, first name,
last name and password.
"""
user = self.create_user(
email,
password=password,
**extra_fields,
)
user.is_admin = True
user.save(using=self._db)
return user
And in your custom user model:
class CustomUser(AbstractBaseUser):
# [...]
objects = MyUserManager()
# [...]
I've taken the code from the django documentation about customizing the User model. They provide an example using the email as the username field (which is what you want).
You may keep the inheritance from AbstractUser but if you do not need most of the things that are in that model, you can also inherit your model from AbstractBaseUser, as in the example.

How to retrieve necessary fields from ModelForms and pass them to views.py properly?

Short background of whole idea: I'm trying to create landing page and for backend I use Python/Django3 framework. I need to create form with such fields as name, surname, email, mobile number and address of customer.
I've decided to save all the information that the user enters in the database, and also send it to my email. In order to connect database to forms I use ModelForms in forms.py section (all the required code will be shown below). In order to connect my email to form I use send_mail function from django.core.mail.
So when a user fills out his form, he is redirected to the 'thank you' page and all the information from the form is saved in the database and sent to my email.
But when I finally wrote the code and started to test functionality, I found out that when I hit 'submit' form button, error <type object 'ClientInfoForm' has no attribute 'cleaned_data'> is raised.
I suppose, that method cleaned_data is wrong in my case and I have to replace it with something else but I don't know with what exactly. All the code will be placed below and any help will be helpful. Thank you!
Models.py file
from django.db import models
class ClientInfo(models.Model):
name = models.CharField(max_length=264)
surname = models.CharField(max_length=264)
email = models.EmailField(max_length=264, unique=True)
mobile_number = models.CharField(max_length=20, unique=True)
address = models.CharField(max_length=264)
def __str__(self):
return f'Client: {self.name} {self.surname}'
Forms.py file
from django import forms
from landing_page.models import ClientInfo
class ClientInfoForm(forms.ModelForm):
class Meta():
model = ClientInfo
fields = '__all__'
Views.py file
from django.shortcuts import render
from landing_page.forms import ClientInfoForm
from django.core.mail import send_mail
def thanks(request):
return render(request, 'landing_page/thanks.html')
def index(request):
form = ClientInfoForm()
if request.method == 'POST':
form = ClientInfoForm(request.POST)
if form.is_valid():
form.save(commit=True)
name = ClientInfoForm.cleaned_data['name']
surname = ClientInfoForm.cleaned_data['surname']
email = ClientInfoForm.cleaned_data['email']
mobile_number = ClientInfoForm.cleaned_data['mobile_number']
address = ClientInfoForm.cleaned_data['address']
send_mail(
f'New client: {name} {surname}',
f'Client Name: {name}\nClient Surname: {surname}\nClient email: {email}\n'
f'Client Mobile Number: {mobile_number}\nClient address: {address}',
email,
['zombe#yandex.ru'],
)
return thanks(request)
else:
print('ERROR FORM INVALID')
return render(request, 'landing_page/index.html', {'form':form})
guys, in case you all interested I found out what was the actual problem. I just had to change this code below
name = ClientInfoForm.cleaned_data['name']
surname = ClientInfoForm.cleaned_data['surname']
email = ClientInfoForm.cleaned_data['email']
mobile_number = ClientInfoForm.cleaned_data['mobile_number']
address = ClientInfoForm.cleaned_data['address']
To this version
name = form.cleaned_data['name']
surname = form.cleaned_data['surname']
email = form.cleaned_data['email']
mobile_number = form.cleaned_data['mobile_number']
address = form.cleaned_data['address']

How to Allow Superusers to access Django Admin Panels

I have the below code for Custom Users Model.
Can anyone help me out me with a Solution to restrict Access to Admin Site for Super Users only . Thanks in advance
# UserManager is for Custom User Model to override Django's Default Model
class UserManager(BaseUserManager):
def _create_user(self, email, password, is_superuser, **extra_fields):
if not email or not password:
raise ValueError("The given username or password must not be null")
user = self.model(
email=email,
password=password,
is_superuser=is_superuser,
last_login=now,
**extra_fields
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, password=None, **extra_fields):
return self._create_user(email, password, False, **extra_fields)
def create_superuser(self, email, password=None, **extra_fields):
return self._create_user(email, password, True, **extra_fields)
class Users(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
created_at_utc = models.DateTimeField(auto_now_add=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['password']
def __str__(self):
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 self.is_admin
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
class Meta:
db_table = "users"
I have the above code for Users, and following Code for Admin Panel to create and update User's
Can anyone help me out me with a Solution to restrict Access to Admin Site for Super Users only . Thanks in advance
class UserCreateForm(UserCreationForm):
class Meta:
model = Users
fields = (
"email","is_admin","is_superuser",
)
class UserChangeForm(BaseUserChangeForm):
class Meta:
model = Users
fields = (
"email","is_admin",
)
class UserAdmin(BaseAdmin):
form = UserChangeForm
add_form = UserCreateForm
fieldsets = (
(None, {"fields": ("email", "password","is_active","is_admin","is_superuser")}),
)
add_fieldsets = (
(None, {
"classes": ("wide",),
"fields": ("email", "password1", "password2","is_active","is_admin","is_superuser")}
),
)
filter_horizontal = ()
list_display = ("email","is_active", )
list_filter = ("is_active", )
search_fields = ("email",)
ordering = ("email",)
# Register your models here.
admin.site.register(Users, UserAdmin)
I have tried many solutions to restrict only SuperUser's to access the Admin Page when Login details are given. Can anyone help me out me with a Solution to restrict Access to Admin Site for Super Users only . Thanks in advance
I think what you are looking for field is is_staff which is there in
class AbstractUser(AbstractBaseUser, PermissionsMixin):
you can import this user from
from django.contrib.auth.models import AbstractUser
and you will find that it has field named as is_staff, so this is basically boolean field which determines if user has access to login to admin site or not, for more info do google search or find the article below
https://www.webforefront.com/django/adminpermissions.html
I see that you have created function as def is_staff(self): but you are not using field is_staff
Had the same issue. Instead of password=None, change it to password. And pass password=password into the create_user function as you see below, together with username=username:
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, password):
if not email:
raise ValueError('Please add an email address')
if not username:
raise ValueError('Please add an username')
user = self.model(email=self.normalize_email(
email), username=username, password=password)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(email=self.normalize_email(
email), username=username, password=password)
user.is_active = True
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
Hope it works for you

Edit user profiles form without using django admin

I am developing a simple LMS system where I have 3 stakeholders Administrator, Faculty Members and Students. Administrator can create, edit, delete, block and list user accounts, with my developement so far I am able to create and list all users.
Now I am stuck at editing user profile, my requirement is when I click on any listed users it should open my extended/customized user profile in a form and I should have the ability to edit any opened user profile.
Below are my code snippets:
MODELS.PY:
from django.contrib.auth.models import User
class UserInformation(models.Model):
user = models.ForeignKey(User, unique=True)
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
def __str__(self):
return self.user.username
VIEWS.PY (to create user):
def ad_create_user(request):
if request.method == 'POST':
firstname = request.POST['firstname']
lastname = request.POST['lastname']
username = request.POST['username']
password = request.POST['password']
email = request.POST['email']
group = request.POST['group']
degree = request.POST['degree']
cell_no = request.POST['cell_no']
new_user = User.objects.create_user(username, email, password)
new_user.first_name = firstname
new_user.last_name = lastname
new_user.save()
if group == 'option_one':
set_group = 3
new_user.groups.add(3)
userinfo = UserInformation(user=User.objects.get(username=username), degree=Degree.objects.get(pk=degree),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_two':
set_group = 2
new_user.groups.add(2)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_three':
set_group = 1
new_user.groups.add(1)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
return HttpResponseRedirect('/administrator/user_management/')
return render(request, 'MobiApp/create_user.html', {'form': CreateUserForm()})
FORMS.PY (to create user):
class CreateUserForm(forms.Form):
firstname = forms.CharField(max_length=64)
lastname = forms.CharField(max_length=64)
username = forms.CharField(max_length=16)
password = forms.CharField(
widget=forms.PasswordInput(),
)
email = forms.EmailField()
group = forms.ChoiceField(
choices=(
('option_one', "Student"),
('option_two', "Faculty Member"),
('option_three', "Administrator"),
),
widget = forms.RadioSelect,
initial = 'option_one',
)
degree = forms.ModelChoiceField(queryset=Degree.objects.all())
cell_no = forms.CharField()
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.layout = Layout(
Field('firstname', css_class='input-xlarge'),
Field('lastname', css_class='input-xlarge'),
Field('username', css_class='input-xlarge'),
Field('password', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
'group',
'degree',
Field('cell_no', css_class='input-xlarge'),
FormActions(
Submit('create', 'Create!', css_class="btn-primary"),
)
)
I found many questions similar to this but none of them helped me and my requirement is also little different as user is not editing his/her profile but administrator is editing profile of any user.
Just for your information:
I am using Django-Crispy-Forms
When I click on any user of edit profile, its URL will be something like this http://myapp.com/administrator/edit_user/11
where 11 is the user id
Thanks in advance, let me know if you need any further information.
EDIT:Here's my final proposed solution (charlesliam also made a reference to this in his comment)
We will subclass AbstractUser to add extra fields to the user. Obviously, there's other ways of doing this, but using AbstractUser should suffice your requirements. You'd have to syncdb for model changes to propagate.
SETTINGS.PY
AUTH_USER_MODEL = 'app.UserInformation' # Points to our custom User model which we will define in models.py
MODELS.PY
from django.contrib.auth.models import AbstractUser
class UserInformation(AbstractUser):
# user = models.ForeignKey(User, unique=True) <---- Remove this field
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
FORMS.PY
class EditUserForm(forms.ModelForm): #fixed typo. It's forms.ModelForm, not models.ModelForm
class Meta:
model = UserInformation
VIEWS.PY
from forms.py import EditUserForm
def edit_user (request, id):
user = User.objects.get(id=11)
if request.method == 'POST': #If form has been submitted
form = EditUserForm(request.POST, instance=user)
if form.is_valid(): #All good. Validation passed
form.save()
return HttpResponseRedirect('/your-view/') # Redirect after POST
else:
form = EditUserForm(instance=user) # Unbound form
return render(request, 'MobiApp/edit_user.html', {'form': form})
edit_user.html
{% load crispy_forms_tags %}
{% crispy form %}
will give you a pre-populated form with the user instance, which you can edit and POST back.
Now with regards to user authentication, you can check if the currently logged in user is superuser (administrator), and proceed with the form editing logic.
So in your VIEWS.PY:
def edit_user (request, id):
current_user = request.user
if current_user.is_superuser:
...
Alternatively, you can assign the currently logged-in user to any group and then check if the user is member of that group, then proceed with form editing.
I hope that helps.
REFERENCES:
https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/
https://github.com/django/django/blob/master/django/contrib/auth/models.py#L353
https://docs.djangoproject.com/en/dev/topics/auth/customizing/
When to use the Custom User Model in Django 1.5

Resources