Django log user in using class based view - django

I am trying to log a user in, however, my view does not seem to work. The page is rendered and the form is displayed and everything. But when I enter a valid user name and password it just refreshes the page instead of going to success_url. I think it is the way I am implementing my view method. I do not think login(request, user_obj) is being accessed, and if so, so is request.user.is_authenticated().
I also include my login form using
{% if user.is_authenticated %}
{% include 'navbar_in.html' %}
{% else %}
{% include 'navbar_out.html' %}
{% endif %}
It only uses navbar_out.htmlso that is how I know my code is not accessing login(request, user_obj).
User model:
# Create your models here.
class Usermie(models.Model):
# associate fields with django built in user objects
# this provides the authentication that we would need from the django built in utilities
usermie_object = models.OneToOneField(User)
# form fields
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=30, unique=True, blank=False)
email = models.EmailField(max_length=30, unique=True, blank=False, null=False)
first_name = models.CharField(max_length=30, blank=False)
last_name = models.CharField(max_length=30, blank=False)
birthday = models.DateField(blank=False)
password = models.CharField(max_length=50, null=False)
sex = models.CharField(max_length=1, blank=False)
location = models.CharField(max_length=100, null=True)
city = models.CharField(max_length=40, null=True)
province = models.CharField(max_length=40, null=True)
country = models.CharField(max_length=40, null=True)
activated = models.IntegerField() # will be 1 if account is activated, 0 otherwise.
date_created = models.DateTimeField(default=timezone.now) # the time the account is created
date_activated = models.DateTimeField(null=True) # when the account is activated via email
def __str__(self):
return self.username
# create a user object to attach to our forms (SignUp)object
def create_usermie_user_callback(sender, instance, **kwargs):
usermie, new = Usermie.objects.get_or_create(usermie_object=instance)
View:
from .models import Usermie
from django.shortcuts import render
from django.views.generic import View
from .forms import SignUpForm, LoginForm
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.views.generic.base import TemplateView
from django.contrib.auth import authenticate, login, logout
class UserLoginRegistration(View):
form_class = LoginForm
# Use initial to declare the initial value of form fields at runtime.
# For example, you might want to fill in a username field with
# the username of the current session.
initial = {'key': 'value'}
template_name = 'usermie/usertest.html' # template form will be rendered on
success_url = '/usermie/home/' # template for successfully submitted form
def get(self, request, *args, **kwargs):
form_login = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form_login': form_login})
# method for posting form
def post(self, request, *args, **kwargs):
# Accessing form with post data
form_login = self.form_class(request.POST)
# Checking if user is logged in
if request.user.is_authenticated():
# Making sure user does not log in twice,
# just send user to profile.html if already logged in
return HttpResponseRedirect(self.success_url)
# Checking if the form is valid
if form_login.is_valid():
email = form_login.cleaned_data['email']
password = form_login.cleaned_data['password']
# NB! On Django docs Two methods to authenticate user and log them in
# 1 call authenticate
# 2 call login
# Return a user_obj object if the username and password are valid
# otherwise it will return null, the null variable is called None in python
user_obj = authenticate(email=email, password=password)
if user_obj is not None:
if user_obj.is_active:
login(request, user_obj)
return HttpResponseRedirect(self.success_url)
# If authentication failed
else:
return HttpResponseRedirect(self.template_name)
# If form is not being posted, render form to template
else:
form_login = self.form_class(initial=self.initial)
context = {'form_login': form_login}
return render(request, self.template_name, context)
And this is my mark up
<form class="navbar-form navbar-form-out" action="" method="post">
{% csrf_token %}
{% load widget_tweaks %}
<div class="form-group">
<label class="sr-only" for="{{ form_login.email.auto_id }}">{{ form_login.email.label }}</label>
{% render_field form_login.email class="form-control" placeholder=form_login.email.label %}
</div>
<div class="form-group">
<label class="sr-only" for="{{ form_login.auto_id }}">{{ form_login.password.label }}</label>
{% render_field form_login.password class="form-control" placeholder=form_login.password.label %}
{% for hidden in form_login.hidden_fields %}
{{ hidden }}
{% endfor %}
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
<button type="submit" name="" value="form_login" class="btn btn-default">Sign in</button>
</form>

It might be that your user is not active and you don't handle that case. Try something like:
if user_obj.is_active:
login(request, user_obj)
return HttpResponseRedirect(self.success_url)
else:
return HttpResponse("Your account is inactive.")

Related

Check if the user who is making the request is the owner of the data, with "form_valid" django

I'm currently trying to improve my form, I would like to see if the connected user correspond to the user who own the data before rewriting it
The model:
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200, null=True, blank=True)
The view:
class TaskUpdate(LoginRequiredMixin, UpdateView):
model = Task
template_name = "tasks/task_form.html"
form_class = DateInputForm
I already tried to do that:
def form_valid(self, form):
if self.request.user.is_staff and self.object.user != self.request.user:
return super().form_valid(form)
if self.object.user != self.request.user:
form.add_error(None, "You can't do that")
return super().form_invalid(form)
also if I'm not a staff user, I can't have access to the input to select users, so it's automatically assigned.
<form action="" method="post">
<div style="flex-direction: column">
{% csrf_token %}
<div style="margin-bottom: 10px">
{% if admin %}
<label for="user">User name : </label>
{{ form.user }}
{% endif %}
</div>
I also thought of doing an sql query to see if the user who is making the query corresponds to the registered user of the task.
You need to add inside the form_valid
name= Task.objects.get(pk=self.object.id)
After you can set the condition
if name.user != self.request.user:...
now we can verify that the user who posts the form, is the owner

Double users created

I have an issue with my code in the sense that when a student registers, a double instance of the student is created. I don't know what's the problem with these block of code. Please help out,also I don't know how to make a link between a teacher and a student so as to allow the teacher to add results for students.
views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm,UserUpdateForm ,InformationUpdateForm,InformationForm
def home(request):
return render(request, 'student/home.html')
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
a_form=InformationForm(request.POST)
# ####and a_form.is_valid()
if form.is_valid() and a_form.is_valid():
user = form.save()
# form.save()
#finally this get links the models, forms and views for user input and all information is registered
information = a_form.save()
# a_form.save()
user.information.majors=a_form.cleaned_data.get('majors')
user.information.department=a_form.cleaned_data.get('department')
user.information.nationality=a_form.cleaned_data.get('nationality')
user.information.date_of_birth=a_form.cleaned_data.get('date_of_birth')
user.information.passport_number=a_form.cleaned_data.get('passport_number')
user.information.phone_number=a_form.cleaned_data.get('phone_number')
user.information.sex=a_form.cleaned_data.get('sex')
user.save()
information.save()
# for this type user input is for for username,last,first and email is registered
# form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('login')
else:
form = UserRegisterForm()
a_form = InformationForm()
context={'form':form,'a_form':a_form }#,'a_form':a_form
return render(request, 'student/register.html', context)
#login_required
def profile(request):
return render(request, 'student/profile.html')#,context
#login_required
def profile_update(request):
if request.method == 'POST':
u_form=UserUpdateForm(request.POST,instance=request.user)
i_form=InformationUpdateForm(request.POST,request.FILES,instance=request.user.information)
if u_form.is_valid() and i_form.is_valid():
u_form.save()
i_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
else:
u_form=UserUpdateForm(instance=request.user)
i_form=InformationUpdateForm(instance=request.user.information)
context={'u_form': u_form,
'i_form':i_form}
return render(request, 'student/profile_update.html',context)
models.py
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
# CHOICES=[('M','Male'),
# ('F','Female')]
class Information(models.Model):
M='Male'
F='Female'
SELECT_GENDER_CHOICE=[(M, 'Male'),
(F, 'Female')]
########################################################
B='Bachelors'
Ma='Masters'
P='PhD'
SELECT_DEGREE_CHOICE=[(B, 'Bachelors'),
(Ma, 'Masters'),(P, 'PhD')]
#########################################################
Y1='1 year'
Y2='2 year'
Y3='3 year'
Y4='4 year'
Y5='5 year'
SELECT_YEARS_CHOICE=[(Y1, '1 year'),(Y2, '2 year'),(Y3, '3 year'),(Y4, '4 year'),(Y5, '5 year')]
user = models.OneToOneField(User,null=True,on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='student')
nationality=models.CharField(max_length=120,blank=False)
sex=models.CharField(max_length=8,choices=SELECT_GENDER_CHOICE,default=M)
department=models.CharField(max_length=120,blank=False)
years=models.CharField(max_length=120,blank=False,choices=SELECT_YEARS_CHOICE,default=Y1,null=True)
degree=models.CharField(max_length=120,blank=False,choices=SELECT_DEGREE_CHOICE,null=True)
majors=models.CharField(max_length=500,blank=False)
phone_number=models.CharField(max_length=12,blank=False)
passport_number=models.CharField(max_length=50,blank=False)#unique=True)
date_of_birth=models.CharField(max_length=10,blank=False)
report=models.FileField(default='StudentResults/DEFAULT_SHEET.xlsx',upload_to='StudentResults',max_length=500,blank=True)#,null=True
reg_no=models.CharField(max_length=10,null=True,unique=True)
def __str__(self):
return f'{self.passport_number} Information'
def save(self,*args, **kwargs):
super().save(*args, **kwargs)
img=Image.open(self.image.path)
if img.height>300 or img.width>300:
output_size=(300,300)
img.thumbnail(output_size)
img.save(self.image.path)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Information
# CHOICES=[('M','Male'),
# ('F','Female')]
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': 'Email'}))
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Username'}))
first_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'First name'}))
last_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Last name'}))
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Confirm'}))
class Meta:
model = User
fields = ['username','first_name','last_name', 'email', 'password1', 'password2']
class InformationForm(forms.ModelForm):
#sex=forms.ChoiceField(choices=CHOICES)
department = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Department'}))
majors = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Majors'}))
nationality = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Nationality'}))
date_of_birth = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Date of birth'}))
passport_number = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Passport number'}))
phone_number = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Phone number'}))
class Meta:
model=Information
fields=['department','majors','degree','years','nationality','date_of_birth','passport_number','phone_number','sex']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['email']
# def email(self):
# email = self.cleaned_data.get("email")#this gets the default title but does not override the required field
# #you can have multiple nested if else/elif statements. You can use this for email validation
# if not ".com" in email:
# raise forms.ValidationError("This is not a email")
# else:
# return email
class InformationUpdateForm(forms.ModelForm):
class Meta:
model=Information
fields=['phone_number']
signals.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Information
#receiver(post_save,sender=User)
def create_information(sender,instance,created,**kwargs):
if created:
Information.objects.create(user=instance)
#receiver(post_save,sender=User)
def save_information(sender,instance,**kwargs):
instance.information.save()
student-profile-page
{% extends "student/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.information.image.url }}">
<div class="media-body">
<p class="text-secondary">Username: {{ user.username }}</p>
<p class="text-secondary">First Name: {{ user.first_name }}</p>
<p class="text-secondary">Last Name: {{ user.last_name }}</p>
<p class="text-secondary">Email: {{ user.email }}</p>
<p class="text-secondary">Passport Number: {{ user.information.passport_number }}</p>
<p class="text-secondary">Date of Birth: {{ user.information.date_of_birth }}</p>
<p class="text-secondary">Sex: {{ user.information.sex }}</p>
<p class="text-secondary">Phone Number: {{ user.information.phone_number }}</p>
<p class="text-secondary">Nationality: {{ user.information.nationality }}</p>
<p class="text-secondary">Majors: {{ user.information.majors }}</p>
<p class="text-secondary">Depatrment: {{ user.information.department }}</p>
<p class="text-secondary">Results: {{ user.information.result }}</p>
<p class="text-secondary">Years: {{ user.information.years }}</p>
<p class="text-secondary">Degree: {{ user.information.degree }}</p>
<a class="btn btn-outline-info" href="{{ user.information.report.url}}">Download your Report</a>
</div>
</div>
{% comment %} <form method="POST">
{% csrf_token %}
<fieldset class="form-group" enctype="multipart/form-data">
<legend class="border-bottom mb-4">Profile Info</legend>
{{ i_form|crispy }}
{{ u_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update</button>
</div>
</form>
</div> {% endcomment %}
{% endblock content %}
That is because you are saving a_form.save() then again saving user.information.save(). You need to change the code like this:
user = form.save()
information = a_form.save(commit=False)
information.user = user
information.save()
messages.success(request, 'Your account has been created! You are now able to log in')
return redirect('login')
You can remove the rest of the code regarding user.information and remove the signals as well. You do not need signals to create Information instance because you have forms to do that.
You are getting double instance of user because of create_information signal.
user = form.save() in following code will save a User instance.
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
a_form =InformationForm(request.POST)
if form.is_valid() and a_form.is_valid():
# form.save() creates a user, and triggers create_information signal
user = form.save()
information = a_form.save()
Now, you have a signal create_information, which is triggered after a User instance is saved (this signal is a post_save singal).
Your user = form.save() will create a user, and will triggers create_information signal.
#receiver(post_save,sender=User)
def create_information(sender,instance,created,**kwargs):
if created:
Information.objects.create(user=instance)
This save another instance of Information, and since Information model has OneToOne mapping to User, another User instance is also saved.
Side note: You have three Information instances saved as well. One created by create_information signal, one by save_information signal, and third by a_form.save() method. This number can be more if cyclic signals are triggered, but not sure about that, so you'll have to check that by yourself.
Solution:
Firstly, get rid of all singals.
Secondly, add User to Information instance before saving it.
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
a_form =InformationForm(request.POST)
if form.is_valid() and a_form.is_valid():
user = form.save()
information = a_form.save(commit=False)
information.user = user
information.save()

How to pass request.user / user to message in Django

So I want to let a user message another user. I want the 'sender' field automatically to be 'request.user' and the receiver field to be the user whom the sender clicked on through their profile page. How would I go about passing those into the form?
matches.html
<div class="container">
<p>Username: {{ profile }}</p>
<h5>Your Matches:</h5>
{% for item in match %}
<br>
<p>Username: <br>{{ item.username}}</p>
<img src="{{ item.photo.url }}" width="300">
<p>Bio: <br>{{ item.description }}</p>
<br>
{% endfor %}
</div>
forms.py/InstantMessageForm
class InstantMessageForm(forms.ModelForm):
class Meta:
model = InstantMessage
fields = ('receiver','sender','message')
def save(self, commit=True):
user = super(InstantMessageForm, self).save(commit=False)
user.receiver = cleaned_data['receiver']
user.sender = cleaned_data['sender']
user.message = cleaned_data['message']
if commit:
user.save()
return user
views.py/instant_message
def instant_message(request):
if request.method == 'POST':
form = InstantMessageForm(request.POST)
if form.is_valid():
form.save()
return redirect('dating_app:home')
else:
form = InstantMessageForm()
context = {'form':form}
return render(request, 'dating_app/instant_message_form.html',context)
models.py
class InstantMessage(models.Model):
receiver = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name= 'sender',on_delete=models.CASCADE )
message = models.TextField()
class InstantMessage(models.Model):
receiver = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name= 'sender',on_delete=models.CASCADE )
message = models.TextField()
instant_message_form.py
{% extends "dating_app/base.html" %}
{% load bootstrap4 %}
{% block content %}
<h1>Start chatting now!</h1>
<div class='container'>
<form method="post" action="{% url 'dating_app:instant_message' %}" >
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Register</button>
</form>
</div>
{% endblock content %}
You can create a form without the sender field:
class InstantMessageForm(forms.ModelForm):
class Meta:
model = InstantMessage
fields = ('receiver', 'message')
Then in the view, you can inject the request.user as the .sender of .instance wrapped in the form:
from django.contrib.auth.decorators import login_required
#login_required
def instant_message(request):
if request.method == 'POST':
form = InstantMessageForm(request.POST)
if form.is_valid():
form.instance.sender = request.user
form.save()
return redirect('dating_app:home')
else:
form = InstantMessageForm()
context = {'form':form}
return render(request, 'dating_app/instant_message_form.html',context)
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
In order to set the receiver, your url should for example contain the a primary key of the receiver. You can then remove the receiver from the form as well, and thus use:
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
#login_required
def instant_message(request, receiver_id):
if request.method == 'POST':
form = InstantMessageForm(request.POST)
if form.is_valid():
form.instance.sender = request.user
form.instance.receiver = get_object_or_404(get_user_mode(), pk=receiver_id)
form.save()
return redirect('dating_app:home')
else:
form = InstantMessageForm()
context = {'form':form}
return render(request, 'dating_app/instant_message_form.html',context)
You of course need then to alter the urls.py accordingly and the action url, such that it includes the primary key of the receiver.

How to post one html form data into two models in django?

I having a html form consisting of some fields with details and I want to post some details of the form to one model and some details to another model how this can be done?
my models.py
class room(models.Model):
id = models.IntegerField(primary_key=True)
image = models.ImageField(upload_to='images')
content = models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.content
# This is the model for goals
class goal(models.Model):
id=models.IntegerField(primary_key=True)
goal = models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.goal
# This is the model for designs
class design(models.Model):
id=models.IntegerField(primary_key=True)
image = models.ImageField(upload_to='images')
content = models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.content
# This is the model for furniture
class furniture(models.Model):
id=models.IntegerField(primary_key=True)
phrase=models.CharField(max_length=60,default='111111')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.phrase
# This is the users model
class user(models.Model):
username=models.CharField(max_length=20)
email=models.CharField(max_length=50,unique=True)
password=models.CharField(max_length=50,default='0000000')
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.username
class UserRequirement(models.Model):
id=models.IntegerField(primary_key=True)
user=models.ForeignKey(user,on_delete=models.CASCADE)
rooms = models.ForeignKey(room,on_delete=models.CASCADE)
goals = models.ManyToManyField(goal)
styles = models.ManyToManyField(design)
furn = models.ForeignKey(furniture,on_delete=models.CASCADE)
created_at = models.DateTimeField(default=datetime.now)
updated_at = models.DateTimeField(default=datetime.now)
My views.py for posting:
def user_register(request):
if request.method == 'POST':
user_form = UserForm(data=request.POST)
if user_form.is_valid():
username=request.POST["username"]
email = request.POST['email']
password = request.POST['password']
rooms = request.POST['room']
g=goals=request.POST['goal']
g = g.split(',')
s=styles=request.POST['style']
s=s.split(',')
furn=request.POST['furn']
u = user(username=username,password=password,email=email)
u.rooms=room.objects.get(pk=rooms)
goals = goal.objects.filter(pk__in=g)
styles = design.objects.filter(pk__in=s)
u.furn = furniture.objects.get(pk=furn)
u.save()
u.goals.add(*goals)
u.styles.add(*styles)
messages.success(request,'Your project design has been registered')
return render(request,'register.html')
else:
messages.warning(request,'Cant be registered this email already exists')
return render(request,'register.html')
My form.html is
<form action="{% url 'modsy:user_register' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="username">Username</label>
<input type="text" name="username" class="form-control" required>
<div id="uname_error"></div>
</div>
<div class="form-group">
<input type="hidden" name="room" id="name" value="">
</div>
<div class="form-group" >
<input type="hidden" name="goal" id="goal" value="">
</div>
<div class="form-group">
<input type="hidden" name="style" id="style" value=" ">
</div>
<div class="form-group" >
<input type="hidden" name="furn" id="furn" value="">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" name="email" class="form-control" required><br>
<div id="name_error" style="color:red;"></div></div>
<div class="form-group">
<label for="password2">Password</label>
<input type="password" name="password" class="form-control" required>
<div id="pwd_error" style="color:red;"></div>
</div>
<div class="button"><input type="submit" value="Save the Project" style="background-color:#000080;" class="btn btn-secondary btn-block" onclick="return validation(form)">
</form>
Now here I want to post the username email and password to the user model and the user room goal furniture style should be stored in the user_requirement model how it can be done?
My forms.py
from django import forms
from . models import user
from django.contrib.auth.models import User
from . models import UserRequirement
from . models import room
from . models import goal
from . models import design
from . models import furniture
class UserForm(forms.ModelForm):
class Meta:
model = user
fields = ('email',)
def clean_email(self):
# Get the email
email = self.cleaned_data.get('email')
# Check to see if any users already exist with this email as a username.
try:
match = User.objects.get(email=email)
except User.DoesNotExist:
# Unable to find a user, this is fine
return email
raise forms.ValidationError('This email address is already in use.')
class UserRequirementForm(forms.ModelForm):
class Meta:
model = UserRequirement
fields=(user,rooms,goals,styles,furn)
Option 1: Create a form with all the fields you need and override the save method to store the data where you need them. You can use your User model as the base model and add any extra fields you need for other models.
Option 2: Use two different forms and process them separately.
if request.method == 'POST':
user_form = UserForm(data=request.POST)
user_requirement_form = UserRequirementForm(data=request.POST)
if user_form.is_valid() and user_requirement_form.is_valid():
user = user_form.save()
user_requirement = user_requirement_form.save(commit=False)
# Set user
user_requirement.user = user
user_requirement.save()
user_requirement_form.save_m2m()
redirect(...)
else:
# Handle errors
messages.warning(request, 'Please correct the errors below')
else:
# GET
user_form = UserForm()
user_requirement_form = UserRequirementForm()
return render(request,'register.html', {'user_form': user_form, 'requirements_form': user_requirement_form})
Then make sure you actually show the errors in your template, using {{ user_form.errors }} or {{ user_form.email.errors }} depending whether you show all the errors at once or per field.
I think the following approach would help.
Forms.py
class UserForm(forms.ModelForm):
class Meta:
model = user
fields = ['email',]
class UserRequirementForm(forms.ModelForm):
class Meta:
model = UserRequirement
fields=['rooms','goals','styles','furn']
Then 2. Views.py
from .forms import UserForm, UserRequirementForm
from django.shortcuts import redirect, render
def register_user(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
user_requirement_form = UserRequirementForm(request.POST)
if user_form.is_valid() and user_requirement_form.is_valid():
user = user_form.save()
user_requirement = user_requirement_form.save(commit=False)
user_requirement.user = request.user # <- Setting the user to currently logged in user
user_requirement.save()
redirect('name_of_url_to_redirect_to')
else:
user_form = UserForm()
user_requirement_form = UserRequirementForm()
context = {
'user_form': user_form,
'user_requirement_form' : user_requirement_form,
}
return render(request, 'path_to_template.html', context)
Then finally in the template (.html file):
<form method="POST">
{{user_form.as_p}}
{{user_requirement_form.as_p}}
<button type="submit"> Submit</button>
</form>
That should render your form and save data correctly on submit
PS: Avoid adding id field on your models as Django already gives you an id field by default.

The 'profile_picture' attribute has no file associated with it

I am trying to create access my profile but one of my models attributes (profile_picture) is empty and it's causing my profile page to crash. I have set blank=True, and it was working earlier but it has stopped working since and i can't figure out why. If I go to the django admin and manually add a profile then I can visit my profile again and everything works. I guess my question is why can't I view my profile even if the profile_pic attribute is empty? Shouldn't blank=True take care of that?
models.py
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
city = models.CharField(max_length=100, default='')
website = models.URLField(default='')
phone = models.IntegerField(default=0)
profile_picture = models.ImageField(upload_to='profile_pics', blank=True)
def __str__(self):
return self.user.username
views.py
def edit_user_profile(request):
if request.method == 'POST':
form = EditUserProfileForm(request.POST, instance=request.user.userprofile)
if form.is_valid():
form.save()
return redirect('/accounts/profile')
else:
form = EditUserProfileForm(instance=request.user)
args = {'form': form}
return render(request, 'accounts/edit_user_profile.html', args)
Profile.html
<div class="container">
<br>
<h2>{{ user }}</h2>
<br>
<p>Name: {{ user.first_name }} {{ user.last_name }}</p>
<img src="{{ user.userprofile.profile_picture.url }}" width="240px">
<p></p>
<p>Motto: {{ user.userprofile.description }}</p>
<p>Youtube: {{ user.userprofile.website }}</p>
<p>About Me: {{ user.userprofile.city }}</p>
<p>Phone Number: {{ user.userprofile.phone }}</p>
Edit Profile<br>
<!-- if profile is updated succesfully -->
{% if messages %}
{% for message in messages %}
<br><br>{{ message }}
{% endfor %}
{% endif %}
</div>
Again, if I go the Django admin and manually upload a photo I can access my profile but by default it won't work without an image.
Any insight is appreciated
Thanks
It's because of the code {{ user.userprofile.profile_picture.url }} in template.
It always try to find picture's url even if your profile_picture is none.
Just add if/else in template, or add method if you have default image.
ie. if/else in template
{% if user.userprofile.profile_picture %}
<img src="{{ user.userprofile.profile_picture.url }}" width="240px">
{% else %}
<img src="{% static 'your_default_img_path' %}" width="240px">
{% endif %}
Or use method for picture
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
city = models.CharField(max_length=100, default='')
website = models.URLField(default='')
phone = models.IntegerField(default=0)
profile_picture = models.ImageField(upload_to='profile_pics', blank=True)
def __str__(self):
return self.user.username
def get_profile_picture(self):
if self.profile_picture
return profile_picture_url
else:
return 'your_default_img_url_path'
Try this code in views.py
form = EditUserProfileForm(request.POST, request.FILES)
if form.is_valid():
city = form.cleaned_data['city']
description = form.cleaned_data['description']
profile_picture = form.cleaned_data['profile_picture']
website = form.cleaned_data['website']
phone = form.cleaned_data['phone']
EditUser= UserProfile(city =city,
description=description,
profile_picture =profile_picture,
website =website,
phone =phone,
user_id=request.user)
EditUser.save()
return redirect('/accounts/profile')
else:
form = EditUserProfileForm(instance=request.user)
args = {'form': form}
return render(request, 'accounts/edit_user_profile.html', args)