'SignupFormExtra' object has no attribute '_meta' - django

That's my first time using userena in Django. i want to override signup form of userena and now have an error.
from userena import settings as userena_settings
from userena.models import UserenaSignup
from userena.utils import get_profile_model
class SignupFormExtra(SignupForm):
"""
A form to demonstrate how to add extra fields to the signup form, in this
case adding the first and last name.
"""
cellPhone = forms.CharField(label=_(u'CellPhone'),
max_length=30,
required=False)
first_name = forms.CharField(label=_(u'First name'),
max_length=30,
required=False)
last_name = forms.CharField(label=_(u'Last name'),
max_length=30,
required=False)
def save(self):
"""
Override the save method to save the first and last name to the user
field.
"""
# First save the parent form and get the user.
new_user = super(SignupFormExtra, self).save()
# Get the profile, the `save` method above creates a profile for each
# user because it calls the manager method `create_user`.
# See: https://github.com/bread-and-pepper/django-userena/blob/master/userena/managers.py#L65
new_user = get_profile_model()
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.cellPhone = self.cleaned_data['cellPhone']
new_user.save(self)
# Userena expects to get the new user from this form, so return the new
# user.
return new_user
Actually i have class Profile in model.py and referred to userena like this:
class Profile(UserenaBaseProfile):
user = models.OneToOneField(User,
on_delete=models.CASCADE,
unique=True,
verbose_name=_('user'),
related_name='my_profile')
can anyone help me to fix it?

You dont need this part:
new_user = get_profile_model()
you get new_user from previous command, just save it and remove self from the new_user.save()
new_user.save(self) -> new_user.save()
def save(self):
"""
Override the save method to save the first and last name to the user
field.
"""
# First save the parent form and get the user.
new_user = super(SignupFormExtra, self).save()
new_user.first_name = self.cleaned_data['first_name']
new_user.last_name = self.cleaned_data['last_name']
new_user.cellPhone = self.cleaned_data['cellPhone']
new_user.save()
# Userena expects to get the new user from this form, so return the new
# user.
return new_user

Related

How to resolve the error: TypeError at /signup save() missing 1 required positional argument: 'self'

I'm trying to register users using AbstractUser but I'm getting an error. Although I'm getting error, users still get registered but I can't handle login with the registered users.
The error goes thus:
The error goes thus:
The post request
My views.py goes thus:
def signup(request):
if request.method == 'POST':
first_name = request.POST['first-name']
last_name = request.POST['last-name']
username = request.POST['username']
email = request.POST['email']
phone_no = request.POST['phone-no']
password = request.POST['password']
password2 = request.POST['password2']
if password==password2:
if CustomUser.objects.filter(username=username).exists():
messages.info(request, 'Username Taken')
return redirect('signup')
elif CustomUser.objects.filter(email=email).exists():
messages.info(request, 'Email Already Exist')
return redirect('signup')
else:
CustomUser.objects.create_user(first_name=first_name, last_name=last_name, username=username, email=email, phone_no=phone_no, password=password)
CustomUser.save(commit=False)
return redirect('login')
else:
messages.info(request, 'Passwords Not Matching')
return redirect('signup')
else:
return render(request, 'signup.html')
And my models.py:
class CustomUser(AbstractUser):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
username = models.CharField(max_length=100, unique=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=150)
phone_no = models.CharField(max_length=20)
is_end_user = models.BooleanField(default=True)
is_smart_earner = models.BooleanField(default=False)
is_top_user = models.BooleanField(default=False)
Remove the CustomUser.save(commit=False). It makes no sense, the record is created with the .create_user(…) method [Django-doc].
You can only call the .save(…) method [Django-doc] on model objects, since these represent a record in the corresponding table. Using it on the CustomUser class makes not much sense, since it represents a table, and table itself is not altered when creating a record.
Furthermore your .save() call uses a parameter commit=…, but that does not make much sense either: the .save(…) of a ModelForm can accept a commit=… parameter, not the one for a Model.
I would however advise to work with a ModelForm. Such ModelForm can automatically validate unique fields, and save the created user. Django already has a basic ModelForm for this: the UserCreationForm [Django-doc]. With some small changes, it can likely work for your custom user model.

How to create User and User Profile in a single Django Admin form

I am struggling to figure out how to save User Profile for a new user created within Django Admin.
I have a custom User model and a simple user Profile with OneToOneField:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(_('staff'), default=False)
is_active = models.BooleanField(_('active'), default=True)
...
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(_('first name'), max_length=80, blank=False)
last_name = models.CharField(_('last name'), max_length=80, blank=False)
...
I have the following user creation form:
class UserAdminCreationForm(forms.ModelForm):
password1 = forms.CharField(label="Password", widget=forms.PasswordInput)
password2 = forms.CharField(
label="Password confirmation", widget=forms.PasswordInput
)
first_name = forms.CharField(label="First name")
last_name = forms.CharField(label="Last name")
class Meta:
model = User
fields = ("email",)
def save(self, commit=True):
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
My admin Add user form is rendered correctly and includes fields from both User and Profile models. After saving the form, a new user and a new profile are created in the database. However, the first_name and last_name fields in profile table are empty.
What I need to do to ensure that profile is saved together with the new user?
UPDATE
Overwriting the save method and ignoring the commit parameter worked for me:
def save(self, commit=True):
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.save()
profile, created = Profile.objects.update_or_create(user=user)
profile.first_name = self.cleaned_data["first_name"]
profile.last_name = self.cleaned_data["last_name"]
profile.save()
return user
Rather than making a custom form you can edit both models in one admin change form by using an inline.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import Profile
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'Profile'
fk_name = 'user'
class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline, )
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super().get_inline_instances(request, obj)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
Since you're already defining your own custom user model, I would recommend doing away with the profile model entirely. It's just going to cause excess queries retrieving profile fields from the user instances.
UDPATE if you want to continue using your form:
def save(self, commit=True):
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
Profile.objects.update_or_create(
user=user,
defaults={
'first_name': self.cleaned_data['first_name'],
'last_name': self.cleaned_data['last_name'],
}
)
profile.first_name = self.cleaned_data["first_name"]
profile.save()
return user

Custom Admin Creation Form

So in my models I have a specfic profile that has a one to one relationship with a more general profile that has a one to one relationship with the django user model. I want to be able to fill out one form in the django admin and create instances of all three models, with relationships already set up.
I haven't messed around with the django admin too much, so I'm not entirely sure how to make it work. Here is my failed attempt:
class CreateSpecializedProfileAdminForm(forms.ModelForm):
class Meta:
exclude = ['profile']
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField(max_length=30)
password = forms.CharField(max_length=30)
confirm_password = forms.CharField(max_length=30)
def clean(self):
password = self.cleaned_data['password']
confirm_password = self.cleaned_data['confirm_password']
if len(self.cleaned_data['password']) < 6:
raise forms.ValidationError('Password must be at least 6 characters.')
if password != confirm_password:
raise forms.ValidationError('Passwords must match.')
return super(CreateSpecializedProfileAdminForm, self).clean()
def save(self, commit=True):
from django.contrib.auth.models import User
first = self.cleaned_data['first_name']
last = self.cleaned_data['last_name']
email = self.cleaned_data['email']
password = self.cleaned_data['password']
user = User.objects.create_user(email, email, password)
user.first_name = first
user.last_name = last
user.save()
profile = UserProfile()
profile.user_auth = user
profile.save()
specialized_profile = SpecializedProfile()
specialized_profile.profile = profile
specialized_profile.save()
return specialized_profile
class SpecializedProfileAdmin(admin.ModelAdmin):
form = CreateSpecializedProfileAdminForm
admin.site.register(SpecializedProfile, SpecializedProfileAdmin)
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
remove class Meta and move exclude = ['profile'] to ModelAdmin
class SpecializedProfileAdmin(admin.ModelAdmin):
exclude = ['profile']
form = CreateSpecializedProfileAdminForm

Form validation error message is not shown in ModelForm

I have a Model like this:
class Client(models.Model):
user = models.OneToOneField(User)
# True if the signed up user is client
is_client = models.BooleanField(default=True)
# Which company the client represents
company = models.CharField(max_length=200, null=True)
# Address of the company
address = models.CharField(max_length=200, null=True)
company_size = models.ForeignKey(CompanySize, null=True)
account_type = models.ForeignKey(AccountType)
billing_address = models.CharField(max_length=254, null=True)
ModelForm of the above model looks like this:
class ProfileForm(ModelForm):
class Meta:
model = Client
exclude = ['user', 'is_client']
def clean(self):
cleaned_data = super(ProfileForm, self).clean()
if not cleaned_data:
raise forms.ValidationError("Fields are required.")
return cleaned_data
In my views, I am doing like this:
def post(self, request, user_id):
# Get the profile information from form, validate the data and update the profile
form = ProfileForm(request.POST)
if form.is_valid():
account_type = form.cleaned_data['account_type']
company = form.cleaned_data['company']
company_size = form.cleaned_data['company_size']
address = form.cleaned_data['address']
billing_address = form.cleaned_data['billing_address']
# Update the client information
client = Client.objects.filter(user_id=user_id).update(account_type=account_type, company=company,
company_size=company_size, address=address, billing_address=billing_address)
# Use the message framework to pass the message profile successfully updated
#messages.success(request, 'Profile details updated.')
return HttpResponseRedirect('/')
else:
profile_form = ProfileForm()
return render(request, 'website/profile.html', {'form': profile_form})
If all the forms data are filled, it successfully redirects to / but if data are not filled it redirects to website/profile.html with the form. But error messages All fields are required are not shown. What's wrong?
Your error is that you are creating a new form when you want to send the error to template, you need send your object "form" and not "profile_form" for include the error information.
Regards.

Django edit profile issues

The ability for a user to edit their profile using Django Userena all of a sudden doesnt work. It just returns to the same edit page without doing anything. Can anyone see whats wrong with the code. Thanks
forms.py
class EditProfileForm(forms.ModelForm):
""" Base form used for fields that are always required """
first_name = forms.CharField(label=_(u'First name'),
max_length=30,
required=False)
last_name = forms.CharField(label=_(u'Last name'),
max_length=30,
required=False)
def __init__(self, *args, **kw):
super(EditProfileForm, self).__init__(*args, **kw)
# Put the first and last name at the top
new_order = self.fields.keyOrder[:-2]
new_order.insert(0, 'first_name')
new_order.insert(1, 'last_name')
self.fields.keyOrder = new_order
class Meta:
model = get_profile_model()
exclude = ['user']
def save(self, force_insert=False, force_update=False, commit=True):
profile = super(EditProfileForm, self).save(commit=commit)
# Save first and last name
user = profile.user
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
return profile
views.py
enter code heredef profile_edit(request, username, edit_profile_form=EditProfileForm,
template_name='userena/profile_form.html', success_url=None,
extra_context=None, **kwargs):
"""
Edit profile.
Edits a profile selected by the supplied username. First checks
permissions if the user is allowed to edit this profile, if denied will
show a 404. When the profile is successfully edited will redirect to
``success_url``.
:param username:
Username of the user which profile should be edited.
:param edit_profile_form:
Form that is used to edit the profile. The :func:`EditProfileForm.save`
method of this form will be called when the form
:func:`EditProfileForm.is_valid`. Defaults to :class:`EditProfileForm`
from userena.
:param template_name:
String of the template that is used to render this view. Defaults to
``userena/edit_profile_form.html``.
:param success_url:
Named URL which will be passed on to a django ``reverse`` function after
the form is successfully saved. Defaults to the ``userena_detail`` url.
:param extra_context:
Dictionary containing variables that are passed on to the
``template_name`` template. ``form`` key will always be the form used
to edit the profile, and the ``profile`` key is always the edited
profile.
**Context**
``form``
Form that is used to alter the profile.
``profile``
Instance of the ``Profile`` that is edited.
"""
user = get_object_or_404(get_user_model(),
username__iexact=username)
profile = user.get_profile()
user_initial = {'first_name': user.first_name,
'last_name': user.last_name}
form = edit_profile_form(instance=profile, initial=user_initial)
if request.method == 'POST':
form = edit_profile_form(request.POST, request.FILES, instance=profile,
initial=user_initial)
if form.is_valid():
profile = form.save()
if userena_settings.USERENA_USE_MESSAGES:
messages.success(request, _('Your profile has been updated.'),
fail_silently=True)
if success_url: redirect_to = success_url
else: redirect_to = reverse('userena_profile_detail', kwargs={'username': username})
return redirect(redirect_to)
if not extra_context: extra_context = dict()
extra_context['form'] = form
extra_context['profile'] = profile
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)
You have to run the following command to solve the problem
python manage.py check_permissions
i hope it will solve your problem.Cheers.