django - adding userprofile to registration form. form not submitted - django

I have a registration form and am adding a user profile to add another field.
after the registration form is filled and submitted the form details are not submitted
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Assigned_Group = models.CharField(max_length=500)
def __str__(self):
return self.user.username
views.py
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
profile_form = UserProfileForm(request.POST)
if form.is_valid() and profile_form.is_valid():
user = form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.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 = RegistrationForm()
profile_form = UserProfileForm()
context = {'form': form, 'profile_form':profile_form}
return render(request, 'registration/register.html', context )
def index(request):
if request.user.is_authenticated:
username = request.user.username
else:
username = 'not logged in'
context = {'username':username}
return render(request, 'index.html', context)
urls.py
path('Register/', views.register, name='register'),

in your html page in body you have to insert {% csrf_token %} like:
<html>
<body>
{% csrf_token %}
</body>

Inside your html form you will need to have inserted {% csrf_token %}.
See the django docs on CSRF for more information or if you are using AJAX.
For example your html will then look something like.
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>
Side note from the django docs (which is important).
In the corresponding view functions, ensure that RequestContext is used to render the response so that {% csrf_token %} will work properly. If you’re using the render() function, generic views, or contrib apps, you are covered already since these all use RequestContext.

Related

Django - Form used in editing data from extended user model doesn't show previous data as placeholder

I use following code:
models.py
class Profile(models.Model):
location = models.CharField(max_length=300, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
)
def __str__(self):
return self.imie
views.py
def edit(request):
if request.method == 'POST':
profile = Profile.objects.get(user = request.user)
profile_form = ProfileForm(request.POST, instance = profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, ('Your profile was successfully updated!'))
return redirect('profile')
else:
messages.error(request, ('Please correct the error below.'))
else:
profile = Profile.objects.get(user = request.user)
profile_form = ProfileForm(request.POST, instance = profile)
return render(request, 'edit.html', {
'profile_form': ProfileForm
})
forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('location')
edit.html
<div class="col-md-6 offset-md-3">
<form method="post">
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" class="btn btn-secondary">Save changes</button>
</form>
</div>
Following code should allow the user to edit data stored in Profile model and it does exactly that, however form is loaded empty (without placeholder) and I would like it to display previous values.
Edit: where the link to edit.html is anchored
it's just a simple verions of a profile page where just plain data is displayed
{% for things in logged_in_user_data %}
<ul>
<li>Your location: {{ things.location}}</li>
</ul>
{% endfor %}
with it's views.py
def profile(request):
logged_in_user_data = Profile.objects.filter(user=request.user)
return render(request, 'profile.html', {'logged_in_user_data': logged_in_user_data})
In the case the request is not a POST request you have still written ProfileForm(request.POST, instance = profile). What does this signify? It means that this form is now a bound form and a user has submitted some data to it (which here was empty since the request was not a post request). This causes the form to be rendered empty since it is considered that the user had provided those empty values. Instead you need to not pass request.POST here:
def edit(request):
profile = Profile.objects.get(user = request.user) # Move common line here
if request.method == 'POST':
profile_form = ProfileForm(request.POST, instance = profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, ('Your profile was successfully updated!'))
return redirect('profile')
else:
messages.error(request, ('Please correct the error below.'))
else:
profile_form = ProfileForm(instance=profile) # No `request.POST` here
return render(request, 'edit.html', {
# Typo noted as per comment by #A67John
'profile_form': profile_form
})

Dango: form rendering empty fields when calling with POST and an instance of the model

I want to add an edit option to a template that just retrieves data from a model and displays it. When the edit button is clicked, the form that has been previously filled and saved, should show up being populated with saved data. But in my case, the form is rendering with empty fields and showing "This field is required" above each field. How do i render the form in editable mode with fields pre-populated?
This is the view for first time data saving:
#login_required
def addprofileView(request):
if request.method == "POST":
form = UserProfileForm(request.POST, request.FILES)
if form.is_valid():
new_user_profile = form.save(commit=False)
new_user_profile.user = request.user
new_user_profile.save()
return redirect('add_license')
else:
form = UserProfileForm()
return render(request, 'addprofile.html', {'form': form})
And this is the view for editing and which should return pre-populated form:
#login_required
def editprofileView(request, pk):
ac = get_object_or_404(Account, pk=pk)
if request.method == "POST":
form = UserProfileForm(request.POST, instance=ac)
if form.is_valid():
ac = form.save(commit=False)
ac.user = request.user
ac.save()
return redirect('view_profile', ac.pk)
else:
form=UserProfileForm(instance=ac)
return render(request, 'addprofile.html', {'form': form})
#login_required
def ProfileView(request, pk):
profile = Account.objects.filter(pk = pk)
return render(request, 'userprofile.html', {'pr': profile})
What am I doing wrong?
The template that redirects to the editprofileView:
 {% block content %}
{% for p in pr %} 
Name: {{ request.user.username }} 
Mobile: {{ p.mobile }} 
city: {{ p.city }} 
building no: {{ p.building_no }} 
state: {{ p.state }} 
ZIP: {{ p.zip }} 
Country: {{ p.country }} 
Sex: {{ p.sex }} 
<form action="{% url 'edit_profile' p.pk %}" method="post">
{% csrf_token %}
<input type="submit" value="Edit">
</form>
{% endblock %}
The action URL in this template sends the Account attribute pk to the editprofileView.
Well, the issue is that you are POSTing to that view in the first place. You shouldn't; a POST is for submitting the data. You don't show that button, but it should either be a simple link, or part of a form with method="GET".

Pass PK into model form (not logged in user)

I would like to use a model form on the django.auth user, but I want to be able to pass in the PK to the model to manage other users, not the logged in user.
Is there a way to do this or do I need to create a regular form?
Django admin site is not appropriate for my use case.
Something like (which doesn't work of course...):
View
def edit_user(request,pk):
if request.method == 'POST':
user_form = UserEditForm(queryset=User.objects.get(pk=pk),
data=request.POST)
if user_form.is_valid():
user_form.save()
messages.success(request, 'User updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(queryset=User.objects.get(pk=pk))
return render(request, 'edit_user.html', {'user_form': user_form })
UserEdit Form
class UserEditForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
Template:
% block content %}
<h1>Edit User:</h1>
<p> </p>
<form action="." method="post" enctype="multipart/form-data">
{{ user_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Save changes" class="btn btn-primary"> Manage</p>
</form>
{% endblock %}
Example URL: profile/edit-user/3/
I want the form populated with the PK of the user (the 3 in this case) NOT like my edit your own profile which passes in instance=request.user:
View for profile
def user_profile(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,
data=request.POST)
profile_form = UserProfileEditForm(instance=request.user.profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Profile updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(instance=request.user)
profile_form = UserProfileEditForm(instance=request.user.profile)
return render(request, 'profile_edit.html', {'user_form': user_form,
'profile_form': profile_form})
Still very new to django...
Thanks for your help.
BCBB
You just need to get the user you want and then pass it in to the form as the instance argument, exactly as you did with the logged in user.
def edit_user(request, pk):
user = User.objects.get(pk=pk)
if request.method == 'POST':
user_form = UserEditForm(instance=user,
data=request.POST)
...
else:
user_form = UserEditForm(instance=user)
...

Does not display form.errors when not valid

I use UserCreationForm to render registration form in Django.
class RegisterForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields
The registration view is defined as follows:
def register(request):
form = RegisterForm()
if request.method == 'POST':
form = RegisterForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
context = {'form': form}
return render(request, 'registration/register.html', context)
And the template for this:
{% if form.errors %}
<p>Some Errors occured</p>
{% endif %}
<form action="{% url 'register' %}" method="POST">
{% csrf_token %} {{ form.as_p }}
<input type="submit" value="Register">
</form>
When I submit invalid data, it does not show <p>Some Errors occured</p>, but throws
Exception Type: ValueError
Exception Value:
The view myapp.views.register didn't return an HttpResponse object. It returned None instead.
which means I have to return HttpResponsein the 2nd if/else statement. The other forms work fine and show form.error messages, except this one. What is the problem? Thanks.
form = RegisterForm(request.POST or None, request.FILES or None)
first of all you dont wanna an empty field in your register form so you dont wanna user or None . second you are using request.FILES while you have no FileField in your form . i fixed your form
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
form = RegisterForm()
return render(request, 'registration/register.html',{'form': form})
You need to move the last line back one indent, so it is run both in the case that the request is not a POST and also when it is a POST but the form is not valid.

django authentication view doesnt work properly

When I try to login through the login page of my django project, there is the message User with this Username already exists. Here I used my own authentication view:
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is None:
return HttpResponseRedirect('/logger/bad_login/')
if user.is_active:
login(request, user)
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('/logger/bad_login/')
else:
form = LoginForm()
return render(request, 'logger/login.html', {'form': form})
Later I found django stock auth views and forms. But still want to know why my view doesnt work properly.
urls.py of my logger app, which used also for saving data of users activity
from django.conf.urls import patterns, include, url
from logger import views
urlpatterns = patterns('',
url(r'^$', views.logger_view, name='log'),
url(r'^login/$', views.login_view, name = 'login'),
url(r'^bad_login/$', views.bad_login_view, name = 'bad_login'),
)
And template
{% extends "base.html" %}
{% block title %}Login {% endblock title %}
{% block content %}
<form action="/logger/login/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
LoginForm
class LoginForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'password')
You are using a ModelForm and those will only valid if both the form and the model validation pass.
As you are using the User model, your form does not validate at the model level which is why your view fails.
If you change your login form thus, your view will work as intended:
class LoginForm(forms.Form): # A normal form, not a model form
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
You might also want to fix your view, so your form errors are displayed correctly, and you are utilizing the form correctly as well:
def login_view(request):
form = LoginForm(request.POST or None)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is None:
return HttpResponseRedirect('/logger/bad_login/')
if user.is_active:
login(request, user)
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('/logger/bad_login/')
return render(request, 'logger/login.html', {'form': form})