user.is_authenticated DetailView is coming as True - python-3.x

I have a Users model and exposing the user details via DetailView.
In the template navbar section, currently use is_authenticated to render url as below.
if {% user.is_authenticated %} my_account {% else %} login_url
Now I am exposing the User details via DetailView like
// views.py
class ProfileView(DetailView):
model = User
template_name = 'account/user_profile.html'
// account/user_profile.html
shows the links(```my_account``` or ```login_url```) and user details viz. username,email & location(via separate ProfileModel)
// models.py
import django.contrib.auth.models import User
def Profile(models.Model)
user = models.OnetoOneField(User)
location = models.CharField(max_length=200)
but this results in showing my_account url on user_profile.html page which I understand is due to the auth context user= self.request.user
To change this behaviour I tried changing the DetailView as follows.
class ProfileView(DetailView):
model = User
template_name = 'account/user_profile.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.user.is_authenticated:
print("context:",context['user'].is_authenticated)
return context
else:
context['user'] = None
return context
Is this a recommended way or there are other recommendations,

Related

Redirecting user to another page after submitting the form using get_absolute_url() method

I'm new to django and I'm following a tutorial trying to create a blog. I'm currently working on a page to add posts to the blog and I want the user to be automatically directed to the post page after submitting the form. I tried using get_absolute_url method but got this error:
NoReverseMatch at /my_blog/add_post/
Reverse for 'post-detail' not found. 'post-detail' is not a valid view function or pattern name.
I checked my code to see if I have done anything wrong but I couldn't notice. I appreciate any help in advance.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
STATUS = [
(0, 'Drafted'),
(1, 'Published'),
]
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
published_on = models.DateTimeField(auto_now=True)
content = models.TextField()
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', args=(str(self.id)))
urls.py
from django.urls import path
from .views import PostListView, PostDetailView, AddPostView, UpdatePostView
app_name = 'my_blog'
urlpatterns = [
path('', PostListView.as_view(), name='posts'),
path('post/<int:pk>', PostDetailView.as_view(), name='post-detail'),
path('add_post/', AddPostView.as_view(), name='add-post'),
path('post/edit/<int:pk>', UpdatePostView.as_view(), name='update-post'),
]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
context_object_name = 'latest_post_list'
class PostDetailView(DetailView):
model = Post
template_name = 'my_blog/post_detail.html'
class AddPostView(CreateView):
model = Post
template_name = 'my_blog/add_post.html'
fields = ('__all__')
class UpdatePostView(UpdateView):
model = Post
template_name = 'my_blog/update_post.html'
fields = ['title', 'content']
This is my add post file in the template directory
add_post.html
{% extends 'base.html' %} {% block content %}
<h1>Add post...</h1>
<form method="post">
{% csrf_token %} {{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
You used an app_name, so you should specify this namespace with:
class Post(models.Model):
# …
def get_absolute_url(self):
return reverse('my_blog:post-detail', args=(self.pk,))
The primary key is also passed in a (singleton) tuple, so (self.pk,), not (self.pk).

List Class View didn't return an HttpResponse

I've been trying to get a class-based list view to display all entries under a user's account (applicant), but when loading the page I'm given the following error:
The view jobassessment.views.view didn't return an HttpResponse object. It returned None instead.
To me that sounds like the URL dispatcher isn't running the correct view, but this is my URL file for both the whole site and the jobassessment application and I can't seem to spot the fault.
Site URL.py:
urlpatterns = [
path('admin/', admin.site.urls, name="admin"),
path('accounts/', include('django.contrib.auth.urls'), name="accounts"),
path('applicant/', include('userprofile.urls'), name="applicant"),
path('assessments/', include('jobassessment.urls')),
]
JobAssessment App's URL.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.AssessmentListView.as_view(), name="assessment"),
]
This is my ListView that is called:
class AssessmentListView(LoginRequiredMixin, generic.ListView):
model = Assessment
template_name ='assessments_index.html'
paginate_by = 5
def get(self, request, *args, **kwargs):
# Ensure they have first created an Applicant Profile
if not Applicant.objects.filter(user=self.request.user).exists():
messages.info(request, "You must create a profile before you can view any assessments.")
return redirect('profile_create_form')
def get_queryset(self):
return Assessment.objects.all().filter(applicant=Applicant.objects.filter(user=self.request.user)).order_by('-assessment_stage')
If Applicant of current login user not exists then your if condition fails and since there is no else
part in there so there is no HttpResponse returned from the view. So please add else part if applicant exists and return HttpResponse()
class AssessmentListView(LoginRequiredMixin, generic.ListView):
model = Assessment
template_name ='assessments_index.html'
paginate_by = 5
def get(self, request, *args, **kwargs):
# Ensure they have first created an Applicant Profile
if not Applicant.objects.filter(user=self.request.user).exists():
messages.info(request, "You must create a profile before you can view any assessments.")
return redirect('profile_create_form')
else:
return HttpResponse() #<------ add corresponding HttpResponse if Applicant exists.
def get_queryset(self):
return Assessment.objects.all().filter(applicant=Applicant.objects.filter(user=self.request.user)).order_by('-assessment_stage')
Following the django document on ListView filter it's better to handle it within get_queryset. So for your case it would be something like this:
class AssessmentListView(LoginRequiredMixin, generic.ListView):
model = Assessment
template_name ='assessments_index.html'
paginate_by = 5
def get_queryset(self):
# Ensure they have first created an Applicant Profile
if not Applicant.objects.filter(user=self.request.user).exists():
messages.info(request, "You must create a profile before you can view any assessments.")
return redirect('profile_create_form')
else:
return Assessment.objects.all().filter(applicant=Applicant.objects.filter(user=self.request.user)).order_by('-assessment_stage')

Upload image in Django for specific user

I am trying to upload pic for specific user but nothing happened when i select image and upload it . it not store in db and not even in media folder
setting.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL = '/media/'
View.py
def uploadPic(request):
if request.method == 'POST' and 'SESSION_KEY' in request.session:
form = Profile(
user_id=request.session['SESSION_KEY'],
profile_pic=ProfileForm(request.POST, request.FILES)
)
form.save()
return redirect('home')
else:
form = ProfileForm()
return render(request, 'upload.html', {
'form': form
})
Model.py
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(null=True, blank=True, upload_to='image/')
Form.py
class ProfileForm(forms.ModelForm):
class Meta:
model = ProfileModel
fields = ['profile_pic']
Template
{% extends 'home.html'%}
{% block content %}
{%if user.is_authenticated%}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
{% endif %}
{% endblock %}
Firstly in your form you set model = ProfileModel but your model is Profile correct that:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['profile_pic']
Next in your view in case of a POST request your view is completely wrong. You try to make an instance of Profile and call it form and save it. This is likely failing. Also I assume you write 'SESSION_KEY' in request.session in an attempt to check if the user is logged in, instead use request.user.is_authenticated or in fact disallow anonymous users from accessing your views by using the login_required decorator. Change it like so:
from django.contrib.auth.decorators import login_required
#login_required
def uploadPic(request):
if request.method == 'POST':
form = ProfileForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('home')
else:
form = ProfileForm()
return render(request, 'upload.html', {'form': form})
Note: The indentation of my answer is 4 spaces which is different from your indentation. It is best to indent by 4 spaces for readability. Check about indentation in PEP 8 which is the Style Guide for Python Code.

Django - Updating multiple models from a form - Data does not saved

I have a custom User model to manage some profiles user: is_student, is_professor and is_executive
In this model, in addition, I have the get_student_profile(),get_professor_profile() and get_executive_profile() methods to get the user profiles data of each user from my different views.
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False)
is_professor = models.BooleanField(default=False)
is_executive = models.BooleanField(default=False)
def get_student_profile(self):
student_profile = None
if hasattr(self, 'studentprofile'):
student_profile = self.studentprofile
return student_profile
def get_professor_profile(self):
professor_profile = None
if hasattr(self, 'professorprofile'):
professor_profile = self.professorprofile
return professor_profile
def get_executive_profile(self):
executive_profile = None
if hasattr(self, 'executiveprofile'):
executive_profile = self.executiveprofile
return executive_profile
In addition each profile user is_student, is_professor and is_executive have their own model in where I manage their own data:
class StudentProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
origin_education_school = models.CharField(max_length=128)
current_education_school = models.CharField(max_length=128)
extra_occupation = models.CharField(max_length=128)
class ProfessorProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
class ExecutiveProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
Is of this way that in my User model I override the save() method to denote that the username field of an user which is created, to be equal in their value to the slug belonging to the profile user which will take that user (StudentProfile, ProfessorProfile, ExecutiveProfile):
def save(self, *args, **kwargs):
user = super(User,self).save(*args,**kwargs)
# Creating an user with student, professor and executive profiles
if self.is_student and not StudentProfile.objects.filter(user=self).exists() \
and self.is_professor and not ProfessorProfile.objects.filter(user=self).exists() \
and self.is_executive and not ExecutiveProfile.objects.filter(user=self).exists():
student_profile = StudentProfile(user=self)
student_slug = self.username
student_profile.slug = student_slug
professor_profile = ProfessorProfile(user=self)
professor_slug = self.username
professor_profile.slug = professor_slug
executive_profile = ExecutiveProfile(user=self)
executive_slug = self.username
executive_profile.slug = executive_slug
student_profile.save()
professor_profile.save()
executive_profile.save()
# And so for all possibles profile combinations
To these three profiles which I have three forms in where their own fields are generated
class StudentProfileForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = ('origin_education_school', 'current_education_school',
'extra_occupation')
class ProfessorProfileForm(forms.ModelForm):
class Meta:
model = ProfessorProfile
fields = ('occupation',)
class ExecutiveProfileForm(forms.ModelForm):
class Meta:
model = ExecutiveProfile
fields = ('occupation', 'enterprise_name', 'culturals_arthistic','ecological')
I access to view profile to user through of this URL:
url(r"^profile/(?P<slug>[\w\-]+)/$",
views.account_profiles__update_view,
name='profile'
),
In my function based view account_profiles__update_view() I am managing the request of the user, and creating the form instances (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm) according to the profile to user (is_student, is_professor and is_executive)
#login_required
def account_profiles__update_view(request, slug):
user = request.user
# user = get_object_or_404(User, username = slug)
# empty list
_forms = []
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
# user = get_object_or_404(settings.AUTH_USER_MODEL, username = slug)
if request.method == 'POST':
# Create a list with all formularies in which there is some POST
# operation. This mean if there is one, two or three profiles together
# or individual
formularios =[Form(data = request.POST,instance=profile) for Form in _forms]
if all([form.is_valid() for form in formularios]):
# Only save dato to database if all formularies that send
# the user in their request are correct or well formed in their
# data. Check that all formularies has been filled
for form in formularios:
profile = form.save(commit=False)
profile.user = user
profile.save()
return redirect('dashboard')
else:
formularios = [Form() for Form in _forms]
# Access to class Forms instanced (StudentProfileForm,
# ProfessorProfileForm, ExecutiveProfileForm), through the __class__
# pŕoperty which return the class onlying. An this class have another
# property named __name__ which return the name of string of a class,
# which is the same name with I did name the form classes
# (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm)
# Next I call to their string method to grant that I always will return
# a string and I call to lower.
# The idea with this is place data into a python dictionarie and access
# to it
data = {form.__class__.__name__.__str__().lower(): form for form in formularios}
data['userprofile'] = profile
return render(request, 'accounts/profile_form.html', data,)
And my profile_form.html template I have the following small logic:
<form method="POST">
{% csrf_token %}
{% if userprofile.user.is_student %}
<div align="center"><i>My Student Profile data</i></div>
{% bootstrap_form studentprofileform %}
{{ studentprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_professor %}
<div align="center"><i>My Professor Profile data</i></div>
{% bootstrap_form professorprofileform %}
{{ professorprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_executive %}
<div align="center"><i>My Executive Profile data</i></div>
{% bootstrap_form executiveprofileform %}
{{ executiveprofileform.non_field_errors }}
{% endif %}
<input type="submit" value="Save Changes" class="btn btn-default">
</form>
I wanted to write all these details to comment the following situation which happen to me:
I render the three forms in my template
Only store data related to the latest user profile selected, this mean:
profiles: is_student, is_professor and is_executive
User with is_student profile ... Save data
User with is_professor profile ... Save data
User with is_executive profile ... Save data
User with is_student and is_professor profile: Only save data to is_professor profile. Does not save data in is_student profile forms fields
User with is_student and is_executive profile: Only save data to is_executive profile. Does not save data in is_student profile forms fields
User with is_professor and is_executive profile: Only save data to is_executive profile. Does not save data in is_professor profile forms fields
User with is_student, is_professor and is_executive profiles: Only save data to is_executive profile. Does not save data in is_professor and is_student profile forms fields
In this moment, only is taked in account the latest selected profile user and according to it, save their related data and not other.
This is because in my account_profiles__update_view() function based view I have this if .. sentences logic:
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
But, I unknown if I will should consider perform here all the profiles user combinations possibles and create the same combination of form instances possibles too. Is this factible of perform?
I try perfom account_profiles__update_view() as a class based view, here some code about it but the characterization of profiles and instances forms send to the template, make me that I choose the function based view option.
¿What is the best alternative?
My apologies for the long question, I did want give all details for to better understanding of my code and approach that I want accomplish.
I appreciate highly some support and orientation.
I took the liberty of cleaning some stuff up for you. Let's review each piece.
models.py
There's no need to probe the model with hasattr(). We can rather use the fact that the OneToOneField between a User and a Profile will place a reference on both sides of the relation. This means you can simply override your save() method as follows:
Note: You may rather want to create the Profiles using Signals instead.
from django.conf import settings
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False, help_text="User is student")
is_professor = models.BooleanField(default=False, help_text="User is professor")
is_executive = models.BooleanField(default=False, help_text="User is executive")
USERNAME_FIELD = 'email'
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
if self.is_student and getattr(self, 'studentprofile', None) is None:
StudentProfile.objects.create(
user=self,
slug=self.username
)
if self.is_professor and getattr(self, 'professorprofile', None) is None:
ProfessorProfile.objects.create(
user=self,
slug=self.username
)
if self.is_executive and getattr(self, 'executiveprofile', None) is None:
ExecutiveProfile.objects.create(
user=self,
slug=self.username
)
views.py
Again, let's just use the fact that the OneToOneField on a user will contain a reference to the Profile:
#login_required
def update_view(request):
user = request.user
# Populate Forms and Instances (if applicable)
form_profiles = []
if user.is_student:
form_profiles.append({'form': StudentProfileForm, 'instance': user.studentprofile})
if user.is_professor:
form_profiles.append({'form': ProfessorProfileForm, 'instance': user.professorprofile})
if user.is_executive:
form_profiles.append({'form': ExecutiveProfileForm, 'instance': user.executiveprofile})
if request.method == 'POST':
forms = [x['form'](data=request.POST, instance=x['instance']) for x in form_profiles]
if all([form.is_valid() for form in forms]):
for form in forms:
form.save()
return redirect('dashboard')
else:
forms = [x['form'](instance=x['instance']) for x in form_profiles]
return render(request, 'accounts/profile_form.html', {'forms': forms})
forms.py
Your forms may look something like this:
class StudentProfileForm(forms.ModelForm):
title = "Student Form"
class Meta:
model = StudentProfile
fields = (
'origin_education_school',
'current_education_school',
'extra_occupation',
)
profile_form.html
<form method="post">
{% csrf_token %}
{% for form in forms %}
<h1>{{ form.title }}</h1>
{{ form }}
{% endfor %}
<button type="submit">Submit</button>
</form>
I double-checked, and forms are saved correctly.
P.S. If you would like to use a Class-Based View, you can follow the classes defined by this Gist: https://gist.github.com/michelts/1029336

Edit user profiles form without using django admin

I am developing a simple LMS system where I have 3 stakeholders Administrator, Faculty Members and Students. Administrator can create, edit, delete, block and list user accounts, with my developement so far I am able to create and list all users.
Now I am stuck at editing user profile, my requirement is when I click on any listed users it should open my extended/customized user profile in a form and I should have the ability to edit any opened user profile.
Below are my code snippets:
MODELS.PY:
from django.contrib.auth.models import User
class UserInformation(models.Model):
user = models.ForeignKey(User, unique=True)
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
def __str__(self):
return self.user.username
VIEWS.PY (to create user):
def ad_create_user(request):
if request.method == 'POST':
firstname = request.POST['firstname']
lastname = request.POST['lastname']
username = request.POST['username']
password = request.POST['password']
email = request.POST['email']
group = request.POST['group']
degree = request.POST['degree']
cell_no = request.POST['cell_no']
new_user = User.objects.create_user(username, email, password)
new_user.first_name = firstname
new_user.last_name = lastname
new_user.save()
if group == 'option_one':
set_group = 3
new_user.groups.add(3)
userinfo = UserInformation(user=User.objects.get(username=username), degree=Degree.objects.get(pk=degree),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_two':
set_group = 2
new_user.groups.add(2)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
if group == 'option_three':
set_group = 1
new_user.groups.add(1)
userinfo = UserInformation(user=User.objects.get(username=username),
stakeholder=Stakeholder.objects.get(pk=set_group), cell_number=cell_no)
userinfo.save()
return HttpResponseRedirect('/administrator/user_management/')
return render(request, 'MobiApp/create_user.html', {'form': CreateUserForm()})
FORMS.PY (to create user):
class CreateUserForm(forms.Form):
firstname = forms.CharField(max_length=64)
lastname = forms.CharField(max_length=64)
username = forms.CharField(max_length=16)
password = forms.CharField(
widget=forms.PasswordInput(),
)
email = forms.EmailField()
group = forms.ChoiceField(
choices=(
('option_one', "Student"),
('option_two', "Faculty Member"),
('option_three', "Administrator"),
),
widget = forms.RadioSelect,
initial = 'option_one',
)
degree = forms.ModelChoiceField(queryset=Degree.objects.all())
cell_no = forms.CharField()
helper = FormHelper()
helper.form_class = 'form-horizontal'
helper.layout = Layout(
Field('firstname', css_class='input-xlarge'),
Field('lastname', css_class='input-xlarge'),
Field('username', css_class='input-xlarge'),
Field('password', css_class='input-xlarge'),
Field('email', css_class='input-xlarge'),
'group',
'degree',
Field('cell_no', css_class='input-xlarge'),
FormActions(
Submit('create', 'Create!', css_class="btn-primary"),
)
)
I found many questions similar to this but none of them helped me and my requirement is also little different as user is not editing his/her profile but administrator is editing profile of any user.
Just for your information:
I am using Django-Crispy-Forms
When I click on any user of edit profile, its URL will be something like this http://myapp.com/administrator/edit_user/11
where 11 is the user id
Thanks in advance, let me know if you need any further information.
EDIT:Here's my final proposed solution (charlesliam also made a reference to this in his comment)
We will subclass AbstractUser to add extra fields to the user. Obviously, there's other ways of doing this, but using AbstractUser should suffice your requirements. You'd have to syncdb for model changes to propagate.
SETTINGS.PY
AUTH_USER_MODEL = 'app.UserInformation' # Points to our custom User model which we will define in models.py
MODELS.PY
from django.contrib.auth.models import AbstractUser
class UserInformation(AbstractUser):
# user = models.ForeignKey(User, unique=True) <---- Remove this field
degree = models.ForeignKey(Degree, null=True, blank=True)
stakeholder = models.ForeignKey(Stakeholder)
cell_number = models.CharField(max_length=32, null=True, blank=True)
FORMS.PY
class EditUserForm(forms.ModelForm): #fixed typo. It's forms.ModelForm, not models.ModelForm
class Meta:
model = UserInformation
VIEWS.PY
from forms.py import EditUserForm
def edit_user (request, id):
user = User.objects.get(id=11)
if request.method == 'POST': #If form has been submitted
form = EditUserForm(request.POST, instance=user)
if form.is_valid(): #All good. Validation passed
form.save()
return HttpResponseRedirect('/your-view/') # Redirect after POST
else:
form = EditUserForm(instance=user) # Unbound form
return render(request, 'MobiApp/edit_user.html', {'form': form})
edit_user.html
{% load crispy_forms_tags %}
{% crispy form %}
will give you a pre-populated form with the user instance, which you can edit and POST back.
Now with regards to user authentication, you can check if the currently logged in user is superuser (administrator), and proceed with the form editing logic.
So in your VIEWS.PY:
def edit_user (request, id):
current_user = request.user
if current_user.is_superuser:
...
Alternatively, you can assign the currently logged-in user to any group and then check if the user is member of that group, then proceed with form editing.
I hope that helps.
REFERENCES:
https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/
https://github.com/django/django/blob/master/django/contrib/auth/models.py#L353
https://docs.djangoproject.com/en/dev/topics/auth/customizing/
When to use the Custom User Model in Django 1.5

Resources