I have an app with name account which contain all the models, views, and forms to be used in registering and signing in users.
I have a template that is located outside the app folder that suppose to contain all the forms in account app.
I am having problem trying to get the forms showing in the template.
Can someone help me?
Here are some snippet of codes:
accounts/forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
# Safe from injection, etc.
class UserRegistrationForm(UserCreationForm):
email = forms.EmailField(required = True)
first_name = forms.CharField(max_length=30, required=True)
last_name = forms.CharField(max_length=30, required=True)
class Meta:
model = User
fields = ('username','email','password1', 'password2','first_name','last_name')
def save(self, commit=True):
user = super(UserRegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
accounts/view.py
from forms import UserRegistrationForm
def register_user(request):
if request.POST:
form = UserRegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
form = UserRegistrationForm()
args = {}
# prevent forgery
args.update(csrf(request))
# empty form
args['form'] = form
return render_to_response('signup.html', args)
def register_success(request):
return render_to_response('signup_success.html')
and finally the template, which is not in account folder. It's in the same folder as settings.py
signup.html
{% extends "base.html" %}
{% block content %}
<form action="" method="post"> {% csrf_token %}
<ul>
{{accounts.form.as_ul}}
</ul>
<input type="submit" name="submit" value="Register">
</form>
{% endblock %}
UPDATE
Upon obtaining permission to move the template from the project manager, I moved it to accounts/template, and changed the render to response address.
I have new problem of form not submitting now.
OMG what's going on??
The template should not be in the same directory as settings.py.
It should be in a directory within the accounts app: accounts/templates/signup/html.
If you've configured your Django project correctly then Django should pickup the template after restarting the web server.
as I see you are passing form variable to template,
but you are trying to use accounts.form.
Hope this helps.
Ok the problem lies on my signup.html file. It should have script for onclick and the form should have an id.
{% extends "base.html" %}
{% block content %}
<form action="" method="post" id="form"> {% csrf_token %}
<ul>
{{accounts.form.as_ul}}
</ul>
<input type="submit" name="submit" value="Register" onclick="submit()">
</form>
<script>
function submit() {document.forms["form"].submit();}
</script>
{% endblock %}
Related
views.py
def registerPage(request):
form = UserCreateForm()
if request.method=='POST':
form=UserCreateForm(request.POST)
if form.is_valid():
user=form.save(commit=False)
user.save()
return redirect('home')
return render(request,'base/signup.html',{'form':form})
model.py
class User(AbstractUser):
name = models.CharField(max_length=200,null=True)
email = models.EmailField(unique=True,null=True)
bio=models.TextField(null=True)
avatar = models.ImageField(upload_to='images/',null=True)
USERNAME_FIELD='email'
REQUIRED_FIELDS=['username']
forms.py
class UserCreateForm(UserCreationForm):
class Meta:
model = User
fields = ['name','email','password1','password2','bio','avatar']
htmltemplate
{% include 'main.html' %}
{% block content %}
<div>
<form method="POST">
{% csrf_token %}
{% for field in form %}
{{field.label}}
{{field}}
{% endfor %}
<input type="submit" value="Register" >
</form>
</div>
{% endblock content %}
when ever i try to sign up on html template it doesnt work but if i do it in admin panel it works how can i solve it ?
First of all, it is generally not recommended to mess with the default User model from django. Its better to create a Profile model with a OneToOneField relationship with the user.
Other than that, your issue lies with your form. Since you have avatar which is an ImageField you need to change your form in a way that it can accept FILES.
So what you need to do is change your form like this:
<form method="post" action="" enctype="multipart/form-data" >
When you are writing client-side code:
use multipart/form-data when your form includes any <input type="file"> elements.
In order to make your POST request valid, you need to also receive your FILES on your view. That can be done by changing your code to:
if request.method=='POST':
form=UserCreateForm(request.POST, request.FILES)
if form.is_valid():
....
views.py
def student_login(request):
form = StudentLoginForm()
if request.method == 'POST':
form = StudentLoginForm(data=request.POST)
print(form.is_valid())
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
print(username)
user = authenticate(username=username,password=password)
if user is not None:
login(request,user)
return redirect('index')
else:
messages.error(request,'Invalid username or password!')
else:
messages.error(request,'Invalid username or password!')
context = {'form':form}
return render(request,'student_login.html',context)
models.py
class Student(models.Model):
name = models.CharField(max_length=100)
username = models.CharField(max_length=100,unique=True,default=None)
mobile = models.CharField(max_length=8)
email = models.CharField(max_length=200,unique=True)
password = models.CharField(max_length=200,default=None,unique=True)
total_books_due = models.IntegerField(default=0)
def __str__(self):
return self.name
forms.py
class StudentLoginForm(forms.ModelForm):
class Meta:
model = Student
fields = ['username','password']
widgets = {
'password':forms.PasswordInput(),
}
student_login.html
{% extends 'base.html' %}
<!-- {% load crispy_forms_tags %} -->
{% block content %}
<div class="container">
<br>
<h2>Student Login Form</h2>
<br>
<form method="POST" action="">
{% csrf_token %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">
{{ message }}
</div>
{% endfor %}
{% endif %} <br>
{% for field in form %}
<p>{{ field.label }} </p>
<p>{{ field }} </p>
<br>
{% endfor %}
<br>
<input type="submit" class="btn btn-primary" value="Login">
</form>
</div>
{% endblock %}
I have been trying to change again and again but form.is_valid() is still returning False. I could not figure out the reason that the form is not valid because I have already specify the fields that I want to show and added the csrf_token. Could anyone help me to figure out where is the problem?
Try to use just a simple form and not a ModelForm, as ModelForms in the background work with creating and updating objects.
In this case, ModelForm is validating as if you are trying to create a new Student, causing the already exists failures.
For example, you can write a simple login form like this:
class StudentLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'autofocus': True}))
password = forms.CharField(
label='Password',
strip=False,
widget=forms.PasswordInput,
)
And then in your views, use it as is:
def student_login(request):
form = StudentLoginForm()
if request.method == 'POST':
form = StudentLoginForm(data=request.POST)
if form.is_valid():
user = authenticate(
username=form.cleaned_data.get('username'),
password=form.cleaned_data.get('password'),
)
if user:
login(request, user)
return redirect('index')
messages.error(request, 'Invalid username or password!')
context = {'form':form}
return render(request,'student_login.html',context)
can you please change this line
form = StudentLoginForm(data=request.POST)
to
form = StudentLoginForm(request.POST)
and also why you are validating the fields as you already validating using .is_valid()
function?
Just create a simple form with username and password. Also, the password field should not be unique if you are using plain text.
Better to use inbuilt User model provided by django. If you want to extend fields in User model, use AbstractUser and override the User model. See in documentation https://docs.djangoproject.com/en/3.2/topics/auth/customizing/
I'm following the Wagtail documentation to customize the user model. I want to add an image to the user model.
Django version: 2.0.8,
Wagtail version: 2.1
Problem
After choosing an image with the image chooser field and clicking 'Save', this error shows up:
'No file was submitted. Check the encoding type on the form.'
Code
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
display_image = models.ForeignKey('wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+')
forms.py
from django import forms
from django.utils.translation import ugettext_lazy as _
from wagtail.users.forms import UserEditForm, UserCreationForm
from wagtail.images.widgets import AdminImageChooser
class CustomUserEditForm(UserEditForm):
display_image = forms.ImageField(
widget=AdminImageChooser(), label=_('Autorenbild'))
class CustomUserCreationForm(UserCreationForm):
display_image = forms.ImageField(
widget=AdminImageChooser(), label=_('Autorenbild'))}
edit.html
{% extends "wagtailusers/users/edit.html" %}
{% block extra_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.display_image %}
{% endblock extra_fields %}
{% block extra_js %}
{{ block.super }}
{% include 'wagtailadmin/pages/_editor_js.html' %}
{% endblock extra_js %}
create.html similar
What I've tried so far
The idea to use the AdminImageChooser widget I found here. I had to adjust the forms by adding an forms.ImageField so that the User page displays without error.
Questions
Anyone know why the error occurs and how to fix it?
As stated in the above Google group thread, it seems as adding an image to the user model is 'a bit awkward'. What is a better approach to have an image connected to an user for repetitive usage in a site? A requirement is that the image can be easily changed in Wagtail admin.
Other problem with Wagtail version 2.2
In Settings > User in the admin interface, the window of the AdminImageChooser does not open.
Console shows following JS error:
Uncaught ReferenceError: createImageChooser is not defined
On Django 3.0.7 and wagtail wagtail 2.9, I could solve it like this:
models.py
class User(AbstractUser):
avatar = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
forms.py
It's important to use an ModelChoiceField and not an ImageField, so you are compliant with the AdminImageChooser widget.
from django import forms
from wagtail.images import get_image_model
from wagtail.images.widgets import AdminImageChooser
from wagtail.users.forms import UserCreationForm, UserEditForm
class CustomUserEditForm(UserEditForm):
avatar = forms.ModelChoiceField(
queryset=get_image_model().objects.all(), widget=AdminImageChooser(),
)
class CustomUserCreationForm(UserCreationForm):
avatar = forms.ModelChoiceField(
queryset=get_image_model().objects.all(), widget=AdminImageChooser(),
)
Templates
No need to load any Javascript manually. The widget do it for you.
Any-templates-dir/wagtailusers/users/create.html
{% extends "wagtailusers/users/create.html" %}
{% block extra_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.avatar %}
{% endblock extra_fields %}
Any-templates-dir/wagtailusers/users/edit.html
{% extends "wagtailusers/users/edit.html" %}
{% block extra_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.avatar %}
{% endblock extra_fields %}
Was using the last proposed solution in the same Google groups thread, also got the ReferenceError: createImageChooser is not defined js problem after updating from Wagtail 2.1 to 2.2
Here is how my research went:
Looks like this commit removed direct media js inclusion from _editor_js.html.
Okay, so the solution is to replicate the old behavour, and access the Media subclasses of widgets
First I tried adding the same removed lines to my own edit.html in {% block extra_js %}. Did not work.
Looks like some views return edit_handler, like here. User view does not.
What user view does provide, however, is form variable, in both create and edit views. Let's use it.
And the final solution for me was changing extra_js block in edit.html like so:
{% block extra_js %}
{{ block.super }}
{% include 'wagtailadmin/pages/_editor_js.html' %}
{{ form.media.js }}
{% endblock extra_js %}
models.py
class User(AbstractUser):
first_name = models.CharField(max_length=40, blank=False)
image = models.ImageField(blank=False, null=False, upload_to='image/', default='img/user.jpg')
def __str__(self):
return self.username
'''here you can add a model and their requirements too u can set path to remember one thing that image folder will create in media folder..so don't forget to add that folder there. like if you find it helpful'''
forms.py
class UserRegistrationForm(forms.ModelForm):
confirm_password2 = forms.CharField(widget=forms.PasswordInput,required=False)
class Meta:
model = User
fields = ['first_name','username','password','confirm_password2','image']
def clean(self):
cleaned_data = super(UserRegistrationForm, self).clean()
password = cleaned_data.get("password")
confirm_password2 = cleaned_data.get("confirm_password2")
if password != confirm_password2:
self.add_error('confirm_password2', "Password does not match")
return cleaned_data
'''def clean for password validation and i directly added fields which field i want in it'''
views.py
def Register_view(request):
form = UserRegistrationForm()
if request.method == 'POST':
form = UserRegistrationForm(request.POST, request.FILES)
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get("password")
user.set_password(password)
user.save()
return redirect('login')
return render(request, 'register.html', {'form': form})
''' use request.files to add imagein your form'''
register.html
<form action="{% url 'register' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="body bg-gray">
<div class="form-group">
{{ form.as_p }}
</div>
</div>
<div class="footer">
<button type="submit" class="btn bg-olive btn-block">Sign me up</button>
I already have Account
</div>
</form>
''' user multipart to add image in it'''
For me the solution was to make sure you initialise the image field widget on the create and edit form classes with the AdminImageChooser
from wagtail.users.forms import UserEditForm
from wagtail.images.widgets import AdminImageChooser
class CustomUserEditForm(UserEditForm):
...
mugshot = AdminImageChooser()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['mugshot'].widget = AdminImageChooser()
You need to do this when you subclass the UserCreationForm too.
Django 3.2.6, Wagtail 2.14
I have hard time with such a easy thing (I guess).
My aim is to create two subpages with 2 different forms yet connected with the same user model:
/account/register.html - page only to manage registration (create user with login,email,password)
/account/questionnaire.html - page for UPDATING the same user information such as age,weight,height etc.
I've got 'POST' communicates in server log but nothing appears when I'm checking up django admin site.
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.PositiveIntegerField(blank=False)
weight = models.PositiveIntegerField(blank=False)
height = models.PositiveIntegerField(blank=False)
forms.py
from django import forms
from django.core import validators
from django.contrib.auth.models import User
from account.models import UserProfile
class RegisterUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username','email','password')
class RegisterUserInfoForm(forms.ModelForm):
class Meta():
model = UserProfile
fields = ('age','weight','height')
views.py
from django.shortcuts import render
from account.forms import RegisterUserForm, RegisterUserInfoForm
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.contrib.auth.decorators import login_required
def register(request):
registered = False
if request.method == 'POST':
user_form = RegisterUserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
else:
print(user_form.errors)
else:
user_form = RegisterUserForm()
return render(request,'account/register.html',{
'user_form':user_form,
'registered':registered,
})
#login_required
def questionnaire(request):
if request.method == 'POST':
profile_form = RegisterUserInfoForm(request.POST, instance=request.user)
if profile_form.is_valid():
profile_form.save()
else:
print(profile_form.errors)
else:
profile_form = RegisterUserInfoForm(instance=request.user)
return render(request,'account/questionnaire.html',{
'profile_form':profile_form,
})
register.html
{% extends 'base.html' %}
{% block body_block %}
<div class="container">
<h1>Register</h1>
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
<input type="submit" name="btn btn-primary" value="Save">
</form>
</div>
{% endblock %}
questionnaire.html
{% extends 'base.html' %}
{% block body_block %}
<div class="container">
<h1>questionnaire</h1>
<form method="post">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="" value="Save">
</form>
</div>
{% endblock %}
Your view doesn't receive a POST request because you didn't provide an action attribute to your form tag. So, your form passes your POST request nowhere. Try it like this:
<form action="" method="post">
{% csrf_token %}
{{ user_form.as_p }}
<input type="submit" name="btn btn-primary" value="Save">
</form>
Also, you should definitely check django's built-in generic views: CreateView and UpdateView. They serve exactly for such purposes and makes almost everything for you.
I've got a Django project, which requires users to be able create accounts to access content.
I'm using the UserCreationForm to do this.
In views.py I have
def register_user(request):
if request.method == "POST":
user_form = UserCreationForm(request.POST)
if user_form.is_valid():
new_user = user_form.save(commit=False)
new_user.set_password(user_form.cleaned_data["password1"])
new_user.save()
template = "account/registration/registration_done.html"
context = {"new_user": new_user}
else:
# TODO: Handle exception
raise BaseException
elif request.method == "GET":
user_form = UserCreationForm()
template = "account/registration/register.html"
context = {"user_form": user_form}
else:
raise NotImplementedError
return render(request, template, context=context)
And then my template is:
{% extends "base.html" %}
{% block title %}Create an Account{% endblock %}
{% block content %}
<h1>Create an Account</h1>
<form action="." method="post">
{{ user_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Create my account"></p>
</form>
{% endblock %}
Which works okay. But when the create account form is displayed, it only has fields for the username, password, and password verification. There's no requirement that the user enter a valid email.
What I'd like to do is have a have the user be required to enter an email address, and then send them an email to ensure that the address is valid, and that they have access to is etc.
Surely this is a common enough pattern that there's already a way to implement is using Django's authentication? Or will I need to write all the forms and handling etc myself?
Override the Meta class of the UserCreationForm
In your forms.py
from django.contrib.auth.forms import UserCreationForm
class YourUserCreationForm(UserCreationForm)
class Meta:
fields = ("username", "email")
and use YourUserCreationForm instead