I'm trying to customize the authentication that comes by default in Django with a table of Mysql already made (collaborators).
When I want to register a user (with the command python manage.py createsuperuser) I get the following error:
django.db.utils.OperationalError: (1054, "Unknown column 'collaborators.password' in 'field list'").
That error mentions that the password column does not exist, and indeed I do not have it in the table, is there any way to indicate that the password is obtained from a column called contrasena_general?
I attach my code.
models.py
class MyUserManager(BaseUserManager):
use_in_migrations = True
def create_superuser(self, no_colaborador, nombres_colaborador, apellido_paterno_colaborador, apellido_materno_colaborador,
id_plantel, id_area_colaborador, no_empleado_sup, contrasena_general, empleado_interno):
user = self.model(no_colaborador = no_colaborador, nombres_colaborador = nombres_colaborador,
apellido_paterno_colaborador = apellido_paterno_colaborador, apellido_materno_colaborador = apellido_materno_colaborador,
id_plantel = id_plantel, id_area_colaborador = id_area_colaborador, no_empleado_sup = no_empleado_sup,
contrasena_general = contrasena_general, empleado_interno = empleado_interno,)
user.set_password(contrasena_general)
user.save(using=self._db)
return user
class Colaboradores(AbstractBaseUser):
no_colaborador = models.IntegerField(primary_key=True)
nombres_colaborador = models.CharField(max_length=150)
apellido_paterno_colaborador = models.CharField(max_length=150)
apellido_materno_colaborador = models.CharField(max_length=150)
id_plantel = models.IntegerField()
id_area_colaborador = models.IntegerField()
id_centro_costos = models.IntegerField()
no_empleado_sup = models.IntegerField()
contrasena_general = models.CharField(max_length=100)
empleado_interno = models.CharField(max_length=10)
objects = MyUserManager()
USERNAME_FIELD = "no_colaborador"
class Meta:
managed = False
db_table = 'collaborators'
app_label = "journal"
def __str__ (self):
return self.email
def def_full_name (self):
return self.nombres_colaborador
def has_perm(self, perm, obj=None):
return self.no_colaborador
def has_module_perms(self, app_label):
return self.no_colaborador
# backends.py
class MyAuthBackend(object):
def authenticate(self, no_colaborador, contrasena_general):
try:
user = Colaboradores.objects.get(no_colaborador=no_colaborador)
if user.check_password(contrasena_general):
return user
else:
return None
except Colaboradores.DoesNotExist:
logging.getLogger("error_logger").error("user with login %s does not exists " % login)
return None
except Exception as e:
logging.getLogger("error_logger").error(repr(e))
return None
def get_user(self, no_colaborador):
try:
user = Colaboradores.objects.get(no_colaborador=no_colaborador)
if user.is_active:
return user
return None
except Colaboradores.DoesNotExist:
logging.getLogger("error_logger").error("user with %(no_colaborador)d not found")
return None
# setting.py
...
AUTH_USER_MODEL = 'journal.Colaboradores'
AUTHENTICATION_BACKENDS = ('clientes.backends.MyAuthBackend', 'django.contrib.auth.backends.ModelBackend',)
How could you indicate that the password is obtained from a column in the table that is not called a password?
I think creating your own createsuperuser command would solve this issue.
Ref: Is it possible to make my own createsuperuser command in django?
You can make your based on the the original source code for Django's createsuperuser that can be found on Github.
As you can see from there, there is a constant on line 20 that says:
PASSWORD_FIELD = 'password'
So I guess that since you changed it in the model to contrasena_general, you need to make your own custom command.
Related
The views.py
def login_form_student(request):
if request.method =='POST':
roll_no = request.POST.get('username')
password = request.POST.get('pass')
user = authenticate(request, uniq_id=roll_no,password=password)
if user is not None:
login(request,user)
return redirect('/userdetails/prof_page/')
else:
return redirect('/userdetails/thankyoupage/')
return render(request,'user_interaction/login_form.html')
The custom backend
from .models import user_detail
from django.contrib.auth.backends import ModelBackend
class user_auth_custom(ModelBackend):
def authenticate(self,request,uniq_id,password):
flag = 0
try:
user = user_detail.objects.get(roll_no=uniq_id)
if password == user.password:
flag = 1
return user
except flag == 0:
pass
return None
def get_user(self,user_id):
try:
return user_detail.objects.get(pk=user_id)
except user_detail.DoesNotExist:
return None
The models.py
class user_detail(models.Model):
full_name = models.CharField(max_length=264,null=True)
roll_no = models.CharField(max_length=264,unique=True,primary_key=True)
management_name = models.CharField(max_length=264)
contact_no = models.CharField(max_length=10)
email = models.EmailField(max_length=254)
department = models.CharField(max_length=264)
residential_status = models.CharField(max_length=264)
password = models.CharField(max_length=32,default='fmspsg2020')
last_login = models.DateTimeField(auto_now=True)
I get a Validation Error.
['“18pw13” value must be an integer.']
18pw13 is actually a roll_no.
What should i do?
Should i create a new user_id attribute to the model of IntegerField?
Why don't you just inherit the user model from djangos AbstactBaseUser, it makes it alot easier, because you get all the user functionallity that the Django user provides.
Here is a link:
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-a-custom-user-model
I have tried all previous solutions such as syncdb, migrate, makemigrations etc. I am still not getting the program to work.
My models.py
class Role(models.Model):
ROLE_CHOICES = (
(1,'ADMIN'),
(2,'HR'),
(3,'MGR'),
(4,'EMP'),
)
id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES,primary_key=True)
def ___str___ (self):
return self.get_id_display()
class User(AbstractUser):
roles = models.ManyToManyField(Role)
class Admins(models.Model):
user = models.PositiveSmallIntegerField(choices=Role.ROLE_CHOICES)
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
class HRs(models.Model):
user = models.PositiveSmallIntegerField(choices=Role.ROLE_CHOICES)
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
Then here is my views.py
class AdminSignUpView(CreateView):
model = User
form_class = AdminSignUpForm
template_name = 'form1/signup_form.html'
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'ADMIN'
return super().get_context_data(**kwargs)
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('/form1/forms/')
class HRSignUpView(CreateView):
model = User
form_class = HRSignUpForm
template_name = 'form1/signup_form.html'
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'HR'
return super().get_context_data(**kwargs)
def form_valid(self,form):
user = form.save()
login(self.request, user)
return redirect('/form1/forms')
Here is my forms.py
class AdminSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fname = forms.CharField(max_length=256)
lname = forms.CharField(max_length=256)
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.roles = 1
user.save()
admin1 = Admins.objects.create(user=user)
admin1.first_name.add(*self.cleaned_data.get('fname'))
admin1.last_name.add(*self.cleaned_data.get('lname'))
return user
class HRSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic()
def save(self, commit=True):
user = super().save(commit=False)
user.roles = 2
user.save()
hr1 = HRs.objects.create(user=user)
hr1.first_name.add(*self.cleaned_data.get('fname'))
hr1.last_name.add(*self.cleaned_data.get('lname'))
return user
Finally, here is my error -
OperationalError at /accounts/signup/hr/
no such table: form1_user
Request Method: POST
Request URL: http://127.0.0.1:8000/accounts/signup/hr/
Django Version: 3.0.5
Exception Type: OperationalError
Exception Value:
no such table: form1_user
It doesn't even show me where my mistake is in my code which makes it really hard to fix my problem. Spent hours on the internet trying to find a solution and nothing works.
After creating new models did you create migrations by makemigrations and applied those migrations by migrate
I ran into the same exact error. It did not seem to fix. What I did, is that I copied all the files in that folder into another folder, deleted that folder, created a new one in my project directory, then pasted everything back in (be careful with your urls.py, don't forget to change them). Then I ran the makemigration and migrate commands and it worked smoothly!
Ive been running into a number of problem in relation to using django's custom model. This one in particular is not raising any errors. For some reason after authenticating via steam and returning to the landing page the database tables for both steamuser_user (custom user) and social_auth_usersocialauth are empty. Nothing is being saved, no errors are being displayed etc.
My custom model which is quite similar to the one on django docs official page is as follows:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import BaseUserManager
# Create your models here.
class UserManager(BaseUserManager):
def create_user(self, steamid, username, password=None):
if not steamid:
msg = 'User has no Steam ID set'
raise ValueError(msg)
if not username:
msg = 'User has no name set'
raise ValueError(msg)
user = self.model(steamid=steamid,
username=username)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, steamid, username, password):
super_user = self.create_user(steamid=steamid,
username=username,
password=password)
super_user.is_staff = True
super_user.is_admin = True
super_user.is_mod = True
super_user.save(using=self._db)
return super_user
class User(AbstractBaseUser):
steamid = models.CharField(max_length=20, unique=True)
username = models.CharField(max_length=80)
email = models.EmailField(null=True,blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_mod = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
reputation = models.IntegerField(max_length=6, default=0)
USERNAME_FIELD = 'steamid'
objects = UserManager()
def __unicode__(self):
return self.username
def get_full_name(self):
return self.steamid
def get_short_name(self):
return self.username
The settings I've used are as follows:
SOCIAL_AUTH_USER_MODEL = 'steamuser.User'
AUTH_USER_MODEL = 'steamuser.User'
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',
)
AUTHENTICATION_BACKENDS = (
'social.backends.steam.SteamOpenId',
'django.contrib.auth.backends.ModelBackend',
)
#Steam OpenAuth
SOCIAL_AUTH_STEAM_API_KEY = 'B1D7C629D093D4B72577F2F11DE4EBE2'
LOGIN_URL = '/'
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'
SOCIAL_AUTH_ENABLED_BACKENDS = (
'steam',
)
Any help would be appreciated!
EDIT
Backends steam.py
def get_user_details(self, response):
player = self.get_json(USER_INFO, params={
'key': self.setting('API_KEY'),
'steamids': self._user_id(response)
})
if len(player['response']['players']) > 0:
player = player['response']['players'][0]
details = {'steamid': player.get('steamid'),
'username': player.get('personaname'),
}
else:
details = {}
return details
EDIT 2
Well despite my logical reasoning, I just gave up and created a custom pipeline to create the new steam user as follows:
from django.contrib.auth import get_user_model
def create_steamuser(details, user=None, *args, **kwargs):
if user:
return {'is_new': False}
if not details:
return
try:
steam_user = get_user_model().objects.get(steamid=details['steamid'])
except steam_user.DoesNotExist:
get_user_model().objects.create_user(details['steamid'], details['username'])
return {
'is_new': True,
}
Now I still have the problem where social_user is not being created. I've set the social user model to use my new custom model but there must be something that I am missing.
python-social-auth won't be able to pass the steamid and date_joined parameters to your custom create_user() method in the manager. To make that possible you have three options:
Set =None to those parameters and set some default vaules for them
Override the default create_user pipeline and pass the extra parameters.
Add a custom pipeline function before create_user and fill details with steamid and date_joined, then define SOCIAL_AUTH_STEAM_USER_FIELDS = ('username', 'email', 'steamid', 'date_joined').
I'm using userena 1.2 and Django 1.4. I'm trying to create multiple user profiles but I had no luck following many post found here on SO.
I've create 2 custom Models and a form like so:
class BaseProfile(UserenaBaseProfile):
""" Default profile """
user = models.OneToOneField(User, unique=True, verbose_name = _('user'), related_name='base_profile')
#property # accessing a method as a property
def is_seller(self):
"""Find out if this is a Seller user"""
try:
self.seller
return True
except Seller.DoesNotExist:
return False
def get_profile_type(self):
"""return the profile type model"""
if self.is_seller:
return self.seller
else:
return self.customer
class Seller(BaseProfile):
company = models.CharField(_('Company'),max_length=100, null=True, blank=True,)
class Customer(BaseProfile):
favourite_snack = models.CharField( _('favourite snack'), max_length=5 )
And overridden the Signup form:
class SignupFormExtra(SignupForm):
# stuff in here
def save(self):
# stuff in here
Now the problem is inside the save method.
Based on this answer I've tried to implement a custom manager but I had no luck (I'm a django newbie). The important point that I understood is that the Save method shoud return a Django User, not a userena profile.
def save(self):
user = super(SpamSignupForm,self).save()
new_customer = Customer.objects.create_user()
return new_user
Then I've tried something like this:
def save(self):
new_user = super(SignupFormExtra, self).save()
new_user.save()
customer = Customer(profile = new_user.get_profile(), user=new_user)
customer.save()
return new_user
The get_profile() method will always (I guess) returns the base profile defined in settings.AUTH_PROFILE_MODULE.
Also it seems wrong to me that the author used a profile field in the subprofile as a OneToOne relation to the Baseprofile WHILE implementing a multi-table inheritance, why? It doesn't seem right to me.
class Customer(Baseprofile):
profile = models.OneToOneField(Baseprofile,
unique=True,
verbose_name=_('profile'),
related_name='student')
Yes, basically I've spent a full day trying to figure this out and I'm still lost.
it is better to use django-registration. install and add it to INSTALLED_APPS =(.....'registration',
now create two user in
registration/models.py
.................
class Seller(models.Model):
user=models.OneToOneField(User)
companyname= models.CharField(max_length=100,blank=True)
def __unicode__(self):
return self.user.username
class Customer(models.Model):
user=models.OneToOneField(User)
birth_date = models.DateField(null=True, blank=True)
favourite_snack = models.CharField(max_length=5)
def __unicode__(self):
return self.user.username
in registration/views.py
........
from django.contrib.auth import authenticate, login
from registration.models import Seller,Customer
from django.http import HttpResponse
def auth_login(request,utype):
temp_login='registration/%slogin.html' %utype
try:
username = request.POST['username']
password = request.POST['password']
except KeyError:
return render(request,temp_login)
user = authenticate(username=username, password=password)
if utype=='seller':
try:Seller.objects.get(user=user)
except: return render(request,temp_login,{'errors':True})
if utype=='customer':
try:Customer.objects.get(user=user)
except: return render(request,temp_login,{'errors':True})
if user.is_active:
login(request,user)
return HttpResponseRedirect('/'+request.GET['next'])#,render(request,'%s/home.html' %utype)
return render(request,temp_login,{'errors':True})
edit registration/auth_urls.py
urlpatterns = patterns('',
url(r'^login/(employer|jobseeker)/$',
auth_login,name='auth_login'),
registration/backends/default/views.py
inside class RegistrationView(BaseRegistrationView):
inside def register(self, request, **cleaned_data): add
if self.args[0]=='e': usertype=Seller()
else: usertype=Customer()
usertype.user=new_user
usertype.save()
registration/backends/default/urls.py
add these line
url(r'^register/([ej])/$',
RegistrationView.as_view(),
name='registration_register'),
I have two data models, one is User and other one is ShibUser, ShibUser associate with User by storing User table's id as its Foreign Key.
Here is my ShibUser Table:
+----+--------------+------------------+----------------+
| id | auth_user_id | shib_username | shib_user_role |
+----+--------------+------------------+----------------+
| 1 | 4 | auser#domain.edu | Student |
| 2 | 5 | buser#domain.edu | Student |
+----+--------------+------------------+----------------+
from django.db import models
from askbot.deps.django_authopenid.models import User
class ShibUser(models.Model):
auth_user = models.ForeignKey(User)
shib_username = models.CharField(max_length = 200)
shib_user_role = models.CharField(max_length = 200)
Here is my User (auth_user) table:
+----+----------------+------------+--------+
| id | username | reputation | status |
+----+----------------+------------+--------+
| 4 | aaUser | 1 | w |
| 5 | MrBUser_Cool | 1 | w |
+----+----------------+------------+--------+
Model Definition for User:
class User(models.Model):
"""
Users within the Django authentication system are represented by this
model.
Username and password are required. Other fields are optional.
"""
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and '
'#/./+/-/_ characters'))
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('e-mail address'), blank=True)
password = models.CharField(_('password'), max_length=128)
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.'))
is_superuser = models.BooleanField(_('superuser status'), default=False,
help_text=_('Designates that this user has all permissions without '
'explicitly assigning them.'))
last_login = models.DateTimeField(_('last login'), default=timezone.now)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
groups = models.ManyToManyField(Group, verbose_name=_('groups'),
blank=True, help_text=_('The groups this user belongs to. A user will '
'get all permissions granted to each of '
'his/her group.'))
user_permissions = models.ManyToManyField(Permission,
verbose_name=_('user permissions'), blank=True,
help_text='Specific permissions for this user.')
objects = UserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def __unicode__(self):
return self.username
def natural_key(self):
return (self.username,)
def get_absolute_url(self):
return "/users/%s/" % urllib.quote(smart_str(self.username))
def is_anonymous(self):
"""
Always returns False. This is a way of comparing User objects to
anonymous users.
"""
return False
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = u'%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def set_password(self, raw_password):
self.password = make_password(raw_password)
def check_password(self, raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
hashing formats behind the scenes.
"""
def setter(raw_password):
self.set_password(raw_password)
self.save()
return check_password(raw_password, self.password, setter)
def set_unusable_password(self):
# Sets a value that will never be a valid hash
self.password = make_password(None)
def has_usable_password(self):
return is_password_usable(self.password)
def get_group_permissions(self, obj=None):
"""
Returns a list of permission strings that this user has through his/her
groups. This method queries all available auth backends. If an object
is passed in, only permissions matching this object are returned.
"""
permissions = set()
for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"):
if obj is not None:
permissions.update(backend.get_group_permissions(self,
obj))
else:
permissions.update(backend.get_group_permissions(self))
return permissions
def get_all_permissions(self, obj=None):
return _user_get_all_permissions(self, obj)
def has_perm(self, perm, obj=None):
"""
Returns True if the user has the specified permission. This method
queries all available auth backends, but returns immediately if any
backend returns True. Thus, a user who has permission from a single
auth backend is assumed to have permission in general. If an object is
provided, permissions for this specific object are checked.
"""
# Active superusers have all permissions.
if self.is_active and self.is_superuser:
return True
# Otherwise we need to check the backends.
return _user_has_perm(self, perm, obj)
def has_perms(self, perm_list, obj=None):
"""
Returns True if the user has each of the specified permissions. If
object is passed, it checks if the user has all required perms for this
object.
"""
for perm in perm_list:
if not self.has_perm(perm, obj):
return False
return True
def has_module_perms(self, app_label):
"""
Returns True if the user has any permissions in the given app label.
Uses pretty much the same logic as has_perm, above.
"""
# Active superusers have all permissions.
if self.is_active and self.is_superuser:
return True
return _user_has_module_perms(self, app_label)
def email_user(self, subject, message, from_email=None):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email])
def get_profile(self):
"""
Returns site-specific profile for this user. Raises
SiteProfileNotAvailable if this site does not allow profiles.
"""
if not hasattr(self, '_profile_cache'):
from django.conf import settings
if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
raise SiteProfileNotAvailable(
'You need to set AUTH_PROFILE_MODULE in your project '
'settings')
try:
app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
except ValueError:
raise SiteProfileNotAvailable(
'app_label and model_name should be separated by a dot in '
'the AUTH_PROFILE_MODULE setting')
try:
model = models.get_model(app_label, model_name)
if model is None:
raise SiteProfileNotAvailable(
'Unable to load the profile model, check '
'AUTH_PROFILE_MODULE in your project settings')
self._profile_cache = model._default_manager.using(
self._state.db).get(user__id__exact=self.id)
self._profile_cache.user = self
except (ImportError, ImproperlyConfigured):
raise SiteProfileNotAvailable
return self._profile_cache
I have a form which represent the user profile and I want to show the role of the user, I have import both the objects in my form but I am struggling on how to really get the user role based on User objects username.
Here is the exact place I am trying to add this:
from askbot.shibapp.models import ShibUser
from django.contrib.auth.models import User
def __init__(self, user, *args, **kwargs):
super(EditUserForm, self).__init__(*args, **kwargs)
logging.debug('initializing the form')
shib_user_role = ShibUser.objects.get(auth_user=4)
if askbot_settings.EDITABLE_SCREEN_NAME:
self.fields['username'] = UserNameField(label=_('Screen name'))
self.fields['username'].initial = user.username
self.fields['username'].user_instance = user
self.fields['email'].initial = user.email
self.fields['realname'].initial = user.real_name
self.fields['website'].initial = user.website
self.fields['city'].initial = user.location
if askbot_settings.EDITABLE_SCREEN_NAME:
self.fields['role'].initial = "test_role" (Instead of 'test_role')
I am very new to django world.
Ok so I think you're trying to go from auth.User.username to ShibUser to do this follow the ForeignKeys backwards:
user = User.objects.get(username=username)
# for reverse relationships the foo_set is created by django enabling
# reverse relationship. You can override this by providing a related_name
shibuser = user.shibuser_set.get()
# Alternative syntax
shibuser = user.shibuser_set.all()[0]
From there you can get your ShibUser role. If More than one ShibUser can exist per User then you want to drop the index and will instead have a queryset of ShibUser objects to work with.
If only one ShibUser object can exist per User you should make this a OneToOneField instead of a foreignkey and things become simpler:
shibuser = user.shibuser
Finally you can even start from the ShibUser model and work with it:
shibuser = ShibUser.objects.get(auth_user__username=username)
# Or if you already had the User object instance
shibuser = ShibUser.objects.get(auth_user=user)
Keep in mind several exceptions can be raised around this depending on the approach: the User could not exist or the ShibUser for the given User could not exist. Perhaps more than one ShibUser could be related to a single user and therefore the .get() calls will result in a MultipleObjectsReturned exception. Your schema isn't very tight to your use case it sounds like so I would probably improve that with a OneToOneField