I am using Python socia auth for face-book. I have modified default Django behavior of User Model and removed username field .
I have added this in custom user model : USERNAME_FIELD = 'email'
BUt I am getting this error when trying to login
TypeError at /complete/facebook/
'username' is an invalid keyword argument for this function
I know when it is trying to create user it doesn't find username field and this throwing this error.
I have defined below settings but still my issue remains as it is :
SOCIAL_AUTH_USER_MODEL = 'accounts.User'
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True
Any solution for this ?
I know it's few months since the question was posted, but I hit the same problem and found the solution.
This problem can be solved using pipeline. The default pipeline does this:
def create_user(strategy, details, user=None, *args, **kwargs):
if user:
return {'is_new': False}
fields = dict((name, kwargs.get(name) or details.get(name))
for name in strategy.setting('USER_FIELDS',
USER_FIELDS))
if not fields:
return
return {
'is_new': True,
'user': strategy.create_user(**fields)
}
Override USER_FIELDS in your settings end leave only email. Alternatively you can create completely new create_user method.
i have same issue and solved problem by adding user argument in create user field ..
None: Argument 'username' is needed for social-auth. It is not actually used.
class UserManager(BaseUserManager):
def create_user(self, email,username=None, full_name=None, password='&btCqv"}#,4TWd6A'):
if not email:
raise ValueError("Users must have an email address")
if not password:
raise ValueError("Users must have a password")
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password) # change user password
user.staff = is_staff
user.admin = is_admin
user.is_active = is_active
user.save(using=self._db)
return user
if still problem persist refer: https://github.com/python-social-auth/social-app-django/issues/15#issuecomment-276118574
Related
I found below in Django source code
class AbstractBaseUser(models.Model):
...
def get_username(self):
"""Return the username for this User."""
return getattr(self, self.USERNAME_FIELD)
...
I searched out the whole Django source code, but did not find out where the USERNAME_FIELD was defined.
Can anyone help on this please?
https://github.com/django/django/blob/main/django/contrib/auth/models.py#L377
USERNAME_FIELD was defined in AbstractUser
You can find USERNAME_FIELD in AuthenticationForm class of django which inherites forms.FORM class of Form Api.
It is also defined in models.py in AbstractUser class, refer Django GitHub Code.
It is given in constructor method that is __init__() of AuthenticationForm.
From Django original Code:
class AuthenticationForm(forms.Form):
"""
Base class for authenticating users. Extend this to get a form that accepts
username/password logins.
"""
username = UsernameField(widget=forms.TextInput(attrs={'autofocus': True}))
password = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput(attrs={'autocomplete': 'current-password'}),
)
error_messages = {
'invalid_login': _(
"Please enter a correct %(username)s and password. Note that both "
"fields may be case-sensitive."
),
'inactive': _("This account is inactive."),
}
def __init__(self, request=None, *args, **kwargs):
"""
The 'request' parameter is set for custom auth use by subclasses.
The form data comes in via the standard 'data' kwarg.
"""
self.request = request
self.user_cache = None
super().__init__(*args, **kwargs)
# Set the max length and label for the "username" field.
self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
username_max_length = self.username_field.max_length or 254
self.fields['username'].max_length = username_max_length
self.fields['username'].widget.attrs['maxlength'] = username_max_length
if self.fields['username'].label is None:
self.fields['username'].label = capfirst(self.username_field.verbose_name)
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username is not None and password:
self.user_cache = authenticate(self.request, username=username, password=password)
if self.user_cache is None:
raise self.get_invalid_login_error()
else:
self.confirm_login_allowed(self.user_cache)
return self.cleaned_data
def confirm_login_allowed(self, user):
"""
Controls whether the given User may log in. This is a policy setting,
independent of end-user authentication. This default behavior is to
allow login by active users, and reject login by inactive users.
If the given user cannot log in, this method should raise a
``ValidationError``.
If the given user may log in, this method should return None.
"""
if not user.is_active:
raise ValidationError(
self.error_messages['inactive'],
code='inactive',
)
def get_user(self):
return self.user_cache
def get_invalid_login_error(self):
return ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username': self.username_field.verbose_name},
)
Here focus on __init__() for get clearification about USERNAME_FIELD.
It is used for getting user field from User model or you can normally say for getting username.
You can find it in your local machine using below path:
C:\Users\Username\AppData\Local\Programs\Python\Python39\Lib\site-packages\django\contrib\admin\forms.py.
Remember: AppData folder will only appear if you select hidden items.
I'm currently taking a custom rest API class that is teaching me to build my own custom REST APIs for authentication, as well as creating custom user models.
Im running into a slight problem with the following code base:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import BaseUserManager
# Create your models here.
class UserProfileManager(BaseUserManager):
""" Manager for User Profiles"""
def create_user(self, email, name, password=None):
""" Create a new user profile"""
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, name=name)
""" user.set_password(password) encrypts the passwords as a hash """
user.set_password(password)
""" This allows you to specify which database to use for the user accounts. Django Supports multiple Databases!!! 8D """
user.save(using=self._db)
return user
def create_superusr(self, email, name, password):
""" Create and save a new superuser with given details """
user = self.create_user(email, name, password)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class UserProfile(AbstractBaseUser, PermissionsMixin):
""" Database model for users in system """
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserProfileManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def get_full_name(self):
""" Retrieve Full Name of User"""
return self.name
def get_short_name(self):
""" Retrieve short name of User"""
return self.name
def __str__(self):
"""Return String representation of our User """
return self.email
The primary issue is in the UserProfileManager section, the issue according to the error output is with the create_superuser section.
The error message is the following:
AttributeError: 'UserProfileManager' object has no attribute 'create_superuser'
I've checked to ensure that in my settings.py file to ensure that using the custom model, as well as Ive checked to confirm that the makemigrations and migrations commands have been run. Ive also tested by deleting the init files, as well as the database and rebuilding them.
Ive also tested to ensure that superuser works, and django admin portal is enabled, all of which without the custom user profile works fine, but with it it breaks, so I know my issue should have something to do with the section of code above, but I cant find anything. Ive checked with the official django docs, but Im at a loss at this point.
I found my error. E for Error, as in the e that was missing in def create_superusEr.
Im good now! This site is awesome! Sometimes just asking the question helps to answer it.
I want to edit the login form provided by django and don't want to build a new one because of the security issues. I have looked at other solutions like How to use another field for logging in with Django Allauth? it's a good example but it assigns email id based on mobile number. However I want to add another field that isn't particularly to authenticate just for input based on which redirection is done. I am quite confused about my approach and whether or not it is possible to do so. Kindly suggest. Thanks.
You can do that in your forms.py file by doing this.
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'}))
yourfield = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'yourfield'}))
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
#user_qs = User.objects.filter(username=username)
#if user_qs.count() == 1:
# user = user_qs.first()
if username and password:
user = authenticate(username=username, password=password)
if not user:
raise forms.ValidationError("This user does not exist")
if not user.check_password(password):
raise forms.ValidationError("Incorrect password")
if not user.is_active:
raise forms.ValidationError("This user is no longer active")
return super(UserLoginForm, self).clean(*args, **kwargs)
Apologies if I've misunderstood your question, but here is how I've added extra fields to user registration it which seems pretty straightforward. I've included some extra related methods just to be verbose:
../forms.py:
class CustomRegistrationForm(RegistrationForm):
"""
Form for registering a new user account.
Subclasses should feel free to add any additional validation they
need, but should avoid defining a ``save()`` method -- the actual
saving of collected user data is delegated to the active
registration backend.
"""
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label="Username",
error_messages={'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
email = forms.EmailField(label="E-mail")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
extra_field = forms.CharField([field options])
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The two password fields didn't match.")
return self.cleaned_data
Then, simply set your register URL to use the proper form class:
../urls.py:
url(r'^accounts/register/$', RegistrationView.as_view(form_class=accounts.forms.CustomRegistrationForm), name='registration_register'),
Is this field not part of your standard model, or does your input need to do some extra work? You can set a signal to make some extra magic happen when the user is registered:
from forms import CustomRegistrationForm
def user_created(sender, user, request, **kwargs):
form = CustomRegistrationForm(request.POST)
user_account = get_user_account(user)
user_account.persona = form.data['persona_tier']
user_account.save()
from registration.signals import user_registered
user_registered.connect(user_created)
FYI I'm using django-registration-redux backend but this approach should help get you close regardless.
I have a custom user model based off of AbstractUser and, I use a custom UserManager, I don't know if theres anything special I have to do to get authenticate to work. I know the user is in the db because I can do objects.get(username, password) and it will return the object.
class PassThroughFarmerManager(PassThroughManagerMixin, UserManager):
use_in_migrations = False
class Farmer(FarmStateble, MapPointable, LastRequestStorable, AbstractUser):
last_irrigation_cycle = models.DateTimeField(auto_now_add=False, auto_now=False, null = True, blank=True)
objects = PassThroughFarmerManager.for_queryset_class(FarmerQuerySet)()
Here is an example of my console output,
>>> models.Farmer.objects.get(username='901e2ac5-9324-11e5-81bf-c42c0323e33a').password
u'1223'
>>> u = authenticate(username = '901e2ac5-9324-11e5-81bf-c42c0323e33a', password = '1223')
>>> u
>>> type(u)
<type 'NoneType'>
When you use MyUserModel.objects.create(...), the password is stored in the database in plain text. The call to authenticate does not work, because Django expects the password to be hashed in the database.
Therefore, when you create a user, you need to ensure that the password is hashed, rather than being stored in plain text in the database. You can do this by calling user.set_password('new_password').
The full example in the docs shows a create_user manager method that calls set_password when creating the user. You would then use MyUserModel.objects.create_user(...) instead of MyUserModel.objects.create(...).
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
I am trying to modify my Django project authentication so I can use my own User model.
I have got it working so far, however I am unable to override the "password" field. I want to change the name to "password_hash".
I have tried this manager:
class UserManager(BaseUserManager):
def create_user(self, email_address, full_name, password=None):
if not email_address:
raise ValueError('Users must have an email address')
user = self.model(
email_address = self.normalize_email(email_address),
full_name = full_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email_address, full_name, password_hash):
user = self.create_user(email_address,
password_hash=password_hash,
full_name=full_name,
)
user.is_admin = True
user.save(using=self._db)
return user
However I get the error TypeError: create_superuser() got an unexpected keyword argument 'password'.
How do I stop create_superuser() from expecting "password" and change it to "password_hash". For username I did it by changing the USERNAME_FIELD, however nothing in the documentation suggests a similar method for the password.
Thanks in advance,
Mark
The solution that worked for me was to override this method in my new user model:
def set_password(self, raw_password):
self.password = make_password(raw_password)