django-allauth - Overriding default signup form - django

I'm using this code (in forms.py) for my custom signup form for allauth:
class RegistrationForm(UserCreationForm):
birth_date = forms.DateField(widget=extras.SelectDateWidget(years=BIRTH_DATE_YEARS))
class Meta:
model = get_user_model()
fields = ('username', 'email', 'password1', 'password2', 'first_name', 'last_name', 'gender', 'birth_date', 'city', 'country')
I have of course specified ACCOUNT_SIGNUP_FORM_CLASS in settings.py to point to this form and it displays the fields which I've put in it. However, it does not work on submission, even if I put signup method it never gets invoked. I've tried with the save but still it's the same - it raises an error that one of my custom added fields is blank while creating user and saving it to the database.
So, what's the correct code for achieving this?

I've made it thanks to #rakwen who has found the correct solution here. I wrote my custom adapter and put it in adapters.py in my app:
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def save_user(self, request, user, form, commit=False):
data = form.cleaned_data
user.username = data['username']
user.email = data['email']
user.first_name = data['first_name']
user.last_name = data['last_name']
user.gender = data['gender']
user.birth_date = data['birth_date']
user.city = data['city']
user.country = data['country']
if 'password1' in data:
user.set_password(data['password1'])
else:
user.set_unusable_password()
self.populate_username(request, user)
if commit:
user.save()
return user
Then I've specified ACCOUNT_ADAPTER in settings.py to point to that adapter, and it finally started to work!

In your project setting.py try to add this line:
verify if you have added this:
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
)
ACCOUNT_SIGNUP_FORM_CLASS = "yourapp.forms.customSignupForm"
In app.models
class CustomModel(models.Model):
"""CustomModel docstring."""
city = forms.CharField(max_length=75)
country = forms.CharField(max_length=25)
other....
In app.forms:
class SignForm(forms.ModelForm):
"""SignForm docstring."""
username = forms.CharField(
max_length=30,
)
first_name = forms.CharField(
max_length=30,
)
last_name = forms.CharField(
max_length=30,
)
field...
def myclean():
def signup(self, request, user):
"""You signup function."""
# dont forget to save your model
class Meta:
model = mymodel.CustomModel
fields = [
'city',
'country',
'field...',
]
Try this method work !

Related

Django Attach variables from one step to another

How would I grab the 2nd form and add it to the first form then selectively not allow that user to login. In the Doctorwizard done function.
maybe add a variable status?
etc.
username,password,email,first_name,last_name,verified
views.py
from django.core.files.storage import FileSystemStorage
import os
from django.conf import settings
class DoctorWizard(SessionWizardView):
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'doctor'))
template_name = "registration/signup.html"
form_list = [SignUpForm,verify]
def done(self, form_list, **kwargs):
data=process_data(form_list)
return redirect('home')
forms.py
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = Profile
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2', )
class verify(forms.Form):
verified = forms.ImageField(required=True)
class Meta:
model = Profile
fields = ('verified',)
models.py
class Profile(AbstractUser):
bio = models.TextField(max_length=100, blank=True)
phone_number = PhoneNumberField(max_length=25, region="US")
birth_date = models.DateField(blank = True, null = True)
is_doctor = models.BooleanField(default=False)
verified = models.ImageField(upload_to='media/doctor')
date_created = models.DateTimeField(auto_now_add=True)
avatar = models.ImageField(default='default.png', upload_to='')
def done(self, form_list, **kwargs):
process_data(form_list)
userCreate = form_list[0]
userCreate.save()
username = userCreate.cleaned_data.get('username')
raw_password = userCreate.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
if user:
user.verified=form_list[1].cleaned_data.get('verified')
user.is_doctor=True
user.is_active=False
user.save()
Just grab the user and access it's fields.

I can get user details but I can't work out how to change them?

So, I can get data and it all works but I can't seem to work out how to update it without updating everything, just what the user wants to update,
I came up with this 'update' method below but I can't seem to get it to work.
Any help would be greatly appreciated.
Thanks,
George.
views.py
class UserDetailsAPIView(CreateAPIView):
serializer_class = UserDetailSerializer
queryset = User.objects.all()
permission_classes = (IsAuthenticated,)
def get(self, request):
serializer = UserDetailSerializer(request.user)
return Response(serializer.data)
def update(self, validated_data):
email = validated_data['email']
first_name = validated_data['first_name']
last_name = validated_data['last_name']
phone_number = validated_data['phone_number']
password = validated_data['password']
user_obj = User(
email=email,
first_name=first_name,
last_name=last_name,
phone_number=phone_number
)
user_obj.set_password(password)
user_obj.save()
return validated_data
serializers.py
class UserDetailSerializer(ModelSerializer):
class Meta:
model = User
fields = [
'first_name',
'last_name',
'email',
'phone_number',
'is_active',
'email_confirmed',
'phone_number_confirmed',
'date_joined',
'last_login',
'nick_name',
'id'
]
You almost got it right, what you are trying to do is probably createOrUpdate, hence you better check if the User already exists.
Reference: Look at UserDetail
Notice the link user = get_or_none(User, user_id=user_id), where I first check if the user is present to update particular fields (as seen in the dictionary update_user)

Django UserCreationForm extension

can i add fields like address,city,state,country,pincode and security question and answer to the extension of UserCreationForm that currently contains username,email,password1 and password2. if yes then please illustrate how?
forms.py
class UserCreationForm(UserCreationForm):
email = EmailField(label=_("Email address"), required=True,
help_text=_("Required."))
city= forms.CharField(label= _("City"),max_length=20, required=True)
state= forms.CharField(label= _("State"),max_length=20, required=True)
class Meta:
model = User
fields = ("username", "email", "password1", "password2","city","state")
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
user.city = self.cleaned_data["city"]
user.state = self.cleaned_data["state"]
if commit:
user.save()
return user
Yes just do like you did with email:
class UserCreationForm:
a_field = WhateverField(whatever='whatever'...)
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
The field is now added in your form.
currently you are extending UserCreationForm class if you have other fields in user model then you can use forms.ModelForm and just mention other fields.
for example
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username','name', 'email', 'phone',
'address','city','state', 'first_time']
if you want to use custom form then.
class UserForm(forms.Form):
name = forms.CharField(label= _("Name"))
address = forms.CharField(label=_("Address"))
etc.

Django Addform User

Hey in django admin there is a button "adduser". When I press it I want to show my custom Form. I tried to do the following.
at admin.py
add_form = CustomUserCreationForm
add_fieldsets = (
(None, {'fields': ('username', 'email', 'first_name', 'last_name', 'password1', 'password2',), }),
)
P.S. I think the names interfered with the standard names. Once I renamed the fields from first_name to something custom it kidna started working.
at forms.py
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(max_length=35, label='First name')
last_name = forms.CharField(max_length=35, label='Last name')
email = forms.EmailField(label="Email")
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email',)
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.first_name = first_name
user.last_name = last_name
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
The only charfield that is editable that appears on teh admin-page is the "username". Others just have a label but not an edit-field which is odd. I would like to display all the CharFields I defined in the CustomForm and them to be editable. Thats how my AddUser looks like:
You need to extend the built-in UserCreationForm from django.contrib.auth.forms instead of extending ModelForm.
This way you don't have to override the save method to set the password, however you'll need to add the username, password1 and password2 fields to your form, or it won't pass validation.

using custom user model with django-allauth gives error Cannot resolve keyword 'username' into field. Choices are: activityhistory, app, ....,

I was trying to integrate django-allauth, and I tried to use custom user model. As stated here, I created my model
class Client(AbstractBaseUser):
fname = models.CharField(max_length=50)
lname = models.CharField(max_length=50)
email = models.EmailField(max_length=150, unique=True, db_index=True)
created_at = models.DateTimeField(auto_now_add=True)
state_choices = (
(0, 'Pending'),
(1, 'Active'),
(2, 'Deleted'),
(3, 'Banned'),
)
state = models.SmallIntegerField(choices=state_choices, default=1, editable=False)
objects = ClientManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fname', 'lname']
def save(self, *args, **kwargs):
#########
def get_short_name(self):
return self.fname
def get_full_name(self):
return '%s %s' % (self.fname, self.lname)
def has_perm(self, perm, obj=None):
###########
def has_module_perms(self, app_label):
###########
#property
def is_staff(self):
###########
And the manager
class ClientManager(BaseUserManager):
def create_user(self, fname, lname, email, created_at, state):
user = self.model(fname=fname, lname=lname, email=email, created_at=created_at, state=state)
return user
def create_superuser(self, fname, lname, email, created_at, state):
user = self.create_user(fname=fname, lname=lname, email=email, created_at=created_at, state=state)
user.is_team_player = True
user.save()
return user
Now, for the admin.py I did
class UserCreationForm(forms.ModelForm):
#A form for creating new users
class Meta:
model = models.Client
fields = ('fname', 'lname', 'email')
class UserChangeForm(forms.ModelForm):
#A form for updating users
class Meta:
model = models.Client
fields = ['fname', 'lname', 'email', 'is_admin']
class ClientAdmin(UserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
list_display = ('email', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', )}),
('Personal info', {'fields': ('fname', 'lname')}),
('Permissions', {'fields': ('is_admin',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'fname', 'lname')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.unregister(models.Client)
admin.site.register(models.Client, ClientAdmin)
admin.site.unregister(Group)
In the settings.py I added AUTH_USER_MODEL = 'app.Client'
Now when I go to /admin it gives me the error
ImproperlyConfigured at /admin
Cannot resolve keyword 'username' into field. Choices are: activityhistory, app, created_at, email, emailaddress, fname, id, is_active, is_admin, last_login, lname, logentry, password, socialaccount, state, testdevice
The stack trace tells me that since it treats email as username, and I use username and password for logging in, it gives me this error. Can't I make django ignore this restriction for admin only, or can I change the login mechanism for admin to use email rather than username?
I am trying to use django-allauth for letting a user sign-in through google or signup using his email and password. But its been a tough ride for me till now. If anybody has done that before or knows how to do it easily, pointing me to references would be great.
First, add this to your custom user model:
class Client(AbstractBaseUser):
class Meta:
swappable = 'AUTH_USER_MODEL'
Also, add this to your settings.py file:
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
From the docs:
(...) if your custom user model does not have a username field (again,
not to be mistaken with an e-mail address or user id), you will need
to set ACCOUNT_USER_MODEL_USERNAME_FIELD to None. This will disable
username related functionality in allauth.
That worked for me.
References:
[1] https://github.com/pennersr/django-allauth#custom-user-models
[2] https://code.djangoproject.com/wiki/ContribAuthImprovements