Extending User and UserCreationForm - python

I need your help.
I extending class User and add same field, than extending UserCreationForm, but form is not valid.
Code crash in if form.is_valid().
Please help, why my form is not correctly?
models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile')
nick_name = models.CharField(max_length=15)
My register form
forms.py
class MyRegisterForm(UserCreationForm):
print "OK!"
nick_name = forms.CharField(max_length=30, required=True, widget=forms.TextInput)
print "Ook"
class Meta:
model = UserProfile
def save(self, commit=True):
if not commit:
raise NotImplementedError("Can't create User and UserProfile without database save")
print "Saving..."
user = super(MyRegisterForm, self).save(commit=False)
user.nick_name = self.cleaned_data["nick_name"]
user_profile = UserProfile(user=user, nick_name=self.cleaned_data['nick_name'])
user_profile.save()
print "Saving complete"
return user, user_profile
Register function
views.py
def reg(request):
if request.method =='POST':
form = MyRegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
print username
password1 = form.cleaned_data['password1']
print password1
password2 = form.cleaned_data['password2']
print password2
nick_name = form.cleaned_data['nick_name']
print nick_name
form.clean_username()
if password1 == password2:
new_user = form.save()
return render_to_response('registration/registration_complete.html')
else:
print "Password error"
return render_to_response('registration/registration_fail.html')
else:
print "FORM error" #ТУТ ВАЛИТСЯ :(
return render_to_response('registration/registration_fail.html')
else:
form = UserCreationForm() # An unbound form
return render_to_response('registration/registration_new_user.html', {
'form': form,
},context_instance=RequestContext(request))
In setting
settings.py
AUTH_PROFILE_MODULE = 'registration.UserProfile'
Registration template
registration_new_user.html
{% extends "base.html" %}
{% block content %}
<h1>Registration</h1>
<form action="registration" method="post">
{% if form.error_dict %}
<p class="error">Please fix the error.</p>
{% endif %}
{% if form.username.errors %}
{{ form.username.html_error_list }}
{% endif %}
<label for="id_username">Login:</label><br> {{ form.username }}<br>
{% if form.password1.errors %}
{{ form.password1.html_error_list }}
{% endif %}
<label for="id_password1">pass:</label><br> {{ form.password1 }}<br>
{% if form.password2.errors %}
{{ form.password2.html_error_list }}
{% endif %}
<label for="id_password2">pass(again):</label><br> {{ form.password2 }}<br>
{% if form.nick_name.errors %}
{{ form.nick_name.html_error_list }}
{% endif %}
<label for="id_nick_name">nick:</label><br> {{ form.nick_name }}<br>
<br>
<input type="submit" value="Reg" />
</form>
{% endblock %}

Well, you have several issues in your code. For instance, you override UserCreationForm with MyRegistrationForm and indeed you instantiate the latter when the request is a POST, but when is not, you pass the template a normal UserCreationForm.
You do have a user in your UserCreationForm because this is a ModelForm whose model is UserProfile and there you have defined a user field. So it makes perfect sense that the forms complaint about this when you create it with the POST.
I don't see a very clear solution here because your code is somewhat tricky but first of all, use the same form with both GET and POST request type so this line in your views
form = UserCreationForm() # An unbound form
Would change for this one:
form = MyRegistrationForm() # An unbound form
In the template it won't appear the field user because you don't include them but it is in the form. As you are creating a new user, that field should be set to non-required because no user will be associated with the UserProfile because you are creating the user. You can set it to non-required adding the parameter blank=True to the model:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile', blank=True)
nick_name = models.CharField(max_length=15)
UPDATE:
This is the code for your base class UserCreationForm save method:
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
As you can see, this code assumes that the user has a set_password attribute, in order to fix this, you have to add a def set_password(self, raw_password) method to your UserProfile class. This error happens because the form base class is designed to be used with normal Django User class, any other error you may encounter like this you will probably solve it by adding the fields required to your UserProfile. This one solves like this:
class UserProfile:
...
def set_password(self, raw_password):
# whatever logic you need to set the password for your user or maybe
self.user.set_password(raw_password)
...
I hope this bring some light to the problem. Good luck!

Related

How to update ManytoManyField in UserChangeForm in Django?

I want to update user info with UserChangeForm and things go pretty well except for the ManyToManyField. When I render the page I can see that all user informations are displayed in correct order of each field like user's username will be in the username field but it's blank in manytomanyfield.
#model.py
class Department(models.Model):
name = models.CharField(max_length=100)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('Email Address'), unique=True)
department = models.ManyToManyField(Department)
# some other fields
# forms.py
class EditUserForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ['email', 'department', ..]
widgets = {'department': forms.CheckboxSelectMultiple()}
# view.py
def home(request):
template_name = "app/home.html"
edit_form = EditUserForm(instance=request.user)
if request.method == "POST":
edit_form = EditUserForm(request.POST, instance=request.user)
if edit_form.is_valid():
edit_form.save()
return JsonResponse({'success': True}, status=200)
else:
return JsonResponse({'error': edit_form.errors}, status=400)
return render(request, template_name, {'edit_form': edit_form})
# template
<form action="{% url 'home' %}" method="POST">
<div class="row">
{{edit_form.email}}
{{edit_form.first_name}}
{% for department in edit_form.department %}
<h6 id="checkbox">{{department.tag}} {{department.choice_label}}</h6>
{% endfor %}
</div>
</form>
here is the picture
As you can see the names and email are displaying inside the form field but why all checkboxes are empty? (Checkbox fields are department)
If you just want to render the field you don't need a for loop. You can just use {{edit_form.department}}. In case you need to modify each input field in CheckboxSelectMultiple you should loop through edit_form.department.field.choices.
For example:
{% for choice, value in edit_form.department.field.choices %}
<input type="checkbox" name="{{choice.instance.value}}" value="{{choice.instance.pk}}" id="id_{{choice.instance.value}}">
{% endfor %}
Note that this will work only in django 3.0 and newer.
you need pass the value and the name in the input in your template
{% for value, name in edit_form.fields.department.choices %}
<input type="checkbox" name="{{name}}" value="{{value}}" id="{{name}}">
{% endfor %}

Django form not displaying with Multiple forms rendered to a template in a single view

I have a view which renders 2 forms to a template, but only one renders, the other doesnt display and it doesnt give me any error, but I can see that the form display when I print it in my console.
This is my model for the form not showing
class Organization(models.Model):
name = models.CharField(max_length=255, null=True)
This is the model for the admin, Im inheriting from AbstractUSer
class User(AbstractUser):
is_user = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
This is the form for the model
class OrganizationForm(forms.ModelForm):
name = forms.CharField(max_length=255)
class Meta:
model = Organization
fields = ['name']
This is the form for the Admin
class AdminSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ['username','email']
def save(self, commit=True):
user = super().save(commit=False)
user.is_admin = True
if commit:
user.save()
return user
This is the view which I am calling the multiple forms
def signup(request):
if request.method == 'POST':
adminForm = AdminSignUpForm(request.POST)
orgForm = OrganizationForm(request.POST)
if adminForm.is_valid() and orgForm.is_valid():
adminForm.save()
orgForm.save(commit=False)
username = adminForm.cleaned_data.get('username')
raw_password = adminForm.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('myapp:home')
else:
adminForm = AdminSignUpForm()
orgForm = OrganizationForm()
print(orgForm)
return render(request, 'registration/signup_form.html', {'OrgFrom': orgForm,'Adminform': adminForm})
And this is the template I am rendering the multiple forms
<form enctype="multipart/form-data" method="post" >
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{Adminform.as_p }}
{{ OrgForm.as_p }}
<button type="submit" class="btn btn-success">Sign up</button>
</form>
I expect both forms to be displayed but only the Adminform displays and it gives me no error to work with
There is one typo. You need to use {{ OrgFrom.as_p }} instead of {{ Orgform.as_p }}.

Why does my own login view with my own User model in Django doesn't work?

I have created my own user model in Django:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_active = models.BooleanField(_('active'), default=False)
token_num = models.IntegerField(_('token count'), default=0)
money_num = models.IntegerField(_('money count'), default=0)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
So then i decided to do my own login view. Here it is:
def login(request):
if request.method == "POST":
form = LoginForm(request.POST)
email = request.POST.get('email')
password = request.POST.get('password')
user = authenticate(username=email, password=password)
if user is not None and user.is_active:
login(request, user)
return HttpResponseRedirect("/main/")
else:
form = LoginForm()
return render(request, 'registration/login.html', {'form': form})
Here is my LoginForm:
class LoginForm(forms.Form):
user_email = forms.EmailField(max_length=255)
password = forms.CharField(max_length=255)
class Meta:
model = User
fields = ('email', 'password')
And my login.html:
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="display: none">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color:red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Login</button>
</form>
{% endblock %}
And here is my urls.py:
urlpatterns = [
url(r'^log/$', views.login)
]
So the problem is that when I enter all data at login page the user doesn't log in and I'm not redirected to the main page. The login page is reloading and that's all.
P.S I have already created 1 user with email and password. This user is_active is set to True (1)
I think that the problem is in your LoginForm.
It is not ModelForm, so you can remove the Meta class.
And your email field is called user_email but in the login view, you try to get email from the POST params.
Try to get the consistent name and you should be able to log in.
Your LoginForm has the field user_email but your code access email from request.POST; these need to be the same.
Note, you should probably check form.is_valid() and get the data from form.cleaned_data, rather than direct from the POST. Also note, your form is (correctly) not a ModelForm so the inner Meta class and its contents are irrelevant.

Unable to access UserProfile model fields in templates in Django. Tried {{ user.userprofile }}

I've tried to import {{ user.userprofile. }} and {{ user.userprofile }} with no success. In the django shell I can access the user profile with UserProfile.objects.all().
{{ user. }} works fine, so I think it's an issue with my model, but I've checked the Django docs 'Models', 'database query', and 'model instance reference' and related S/O posts, but if it's my model that's the issue, I don't know what else to search for.
Thanks
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserProfileManager(models.Manager):
pass
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='user')
can_inst_nat = models.BooleanField(verbose_name='I can explain grammar and word usage to people in my NATIVE language.', default=False)
can_inst_tar = models.BooleanField(verbose_name='I can explain grammar and word usage to people in my TARGET language.', default=False)
wants_nat_lang_inst = models.BooleanField(verbose_name='I would like grammar and vocabulary explained to me in my NATIVE language.', default=False)
wants_tar_lang_inst = models.BooleanField(verbose_name='I would like grammar and vocabulary explained to me in my TARGET language.', default=False)
wants_cont = models.BooleanField(verbose_name='I would like to continue working with the same partner for several consecutive exchanges.', help_text='(If you want continuity, check this; If you like speaking to a variety of people, leave it blank.)', default=False)
image = models.ImageField(upload_to='profile_image', blank=True)
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
user = kwargs['instance']
if kwargs['created']:
user_profile = UserProfile(user=user)
user_profile.save()
post_save.connect(create_profile, sender=User)
views.py
def edit_profile(request, pk):
user = User.objects.get(pk=pk)
user_form = EditProfileForm(instance=user)
ProfileInlineFormset = inlineformset_factory(User, UserProfile, fields=[
'image',
'can_inst_nat',
'can_inst_tar',
'wants_nat_lang_inst',
'wants_tar_lang_inst',
'wants_cont',
])
formset = ProfileInlineFormset(instance=user)
if request.user.is_authenticated and request.user.id == user.id:
if request.method == "POST":
user_form = EditProfileForm(request.POST, request.FILES, instance=user)
if user_form.is_valid():
created_user = user_form.save(commit=False)
formset = ProfileInlineFormset(request.POST, request.FILES, instance=created_user)
if formset.is_valid():
created_user.save()
formset.save()
return redirect(reverse('accounts:view_profile'))
return render(request, 'accounts/edit_profile.html', {
"noodle": pk,
"noodle_form": user_form,
"formset": formset,
})
else:
raise PermissionDenied
template
<h4>Preferences</h4>
<p> {{ user.userprofile }}</p>
<ul>
{% if user.profile.can_inst_nat %}
{{ user.userprofile.can_inst_nat }}
<li class="profile-list-item">"I <strong>can explain grammar and word usage</strong> to people <strong>in my <em>native</em> language</strong>."</li><br>
{% endif %}
{% if user.userprofile.can_inst_tar %}
<li class="profile-list-item">"I <strong>can explain grammar and word usage</strong> to people <strong>in my <em>target</em> language</strong>."</li><br>
{% endif %}
{% if user.userprofile.wants_nat_lang_inst %}
<li class="profile-list-item">"I <strong>want grammar and vocab</strong> explained to me <strong>in my <em>native</em> language</strong>."</li><br>
{% endif %}
{% if user.userprofile.wants_tar_lang_inst %}
<li class="profile-list-item">"I <strong>want grammar and vocab</strong> explained to me <strong>in my <em>target</em> language</strong>."</li><br>
{% endif %}
{% if user.userprofile.wants_cont %}
<li class="profile-list-item">"I <strong>want</strong> to continue working with <strong>the same partner</strong> for several <strong>consecutive exchanges</strong>."</li><br>
{% endif %}
</ul>
You have set related_name='user' on the foreign key on you UserProfile model, which means you have to access it with user.user.
related_name defines how you access the reverse relationship, not the forward one, so setting it to user is a bit confusing, and probably isn't how you intended for it to work.
You might consider changing the related_name to "profile" so that you can instead access it as user.profile.
Change the related_name from user to userprofile
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='userprofile')
and to not forget to passe the user into context.

Add placeholder field to basic UserCreation Django sign up form

I am fairly new to Django and I have set up a sign up form with some additional fields.
In my forms.py file I have the following code:
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 = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2', )
In my views.py I have the following code:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('index')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
Then in my signup.html view I am rendering the following:
<form method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button class="btn-contact" type="submit">Let's Go!</button>
</form>
Essentially what I want to do is add placeholder text in each field but this is not appearing the way I have set it up.
To do this I need more control over the forms fields but I don't know how to do that because of the way I am rendering fields in a loop.
How would I go about doing this?
For placeholders, take a look at How do I add a placeholder on a CharField in Django?
One good advice that I have to give you, is that you shouldn't manually render your form, because Django has mechanisms to do that quite well (like {{form.as_p}} in your case). See Working with forms.

Categories

Resources