I’m exploring Class Based Views for the first time and I have a rudimentary Django CMS that is working quite well to my delight. Next I am exploring how to implement Django’s authentication and sessions feature which I can’t seem to get working as intended.
What works:
- Django is serving a template facilitated by a ListView CBV on the landing page at an address like this: http://127.0.0.1:8000/
- The list of hyperlinks presented on that page take the web visitor to the corresponding detail page as indicated by a DetailView and identified by a unique slug.
- I’ve already got a basic custom
login
page: http://127.0.0.1:8000/accounts/login/
and alogout
button which then redirects the user to this location: http://127.0.0.1:8000/accounts/logout/ - I have created non-Admin user credentials which Django will accept. I can add permissions in the Admin Dashboard.
You can see the above listed features by checking out this mirror of my local dev server: https://8ff1-2607-fea8-87e3-3200-00-a0f5.ngrok.io/
However please be advised that Chrome may alert you to a potential phishing attack. To access the site, you may need to bypass the phishing warning.
What doesn’t work:
The problem with the above is that with or without valid credentials, any web visitor can still view all the content.
- When a user is signed out, the web visitor is still able to traverse and descend down into the other content.
- I’m trying to get the home page to present the web visitor with the login page requiring every web visitor to enter their credentials. But right now, Django serves all the other content.
My question: How do I get the User authentication Mixins to properly require valid login credentials? Right now everything is open to the public, even though I have added Mixins and tried implementing a custom LoginView, as described below
What I have tried:
I tried adding this path to my top-level project urls.py
:
from contents.views import CustomLoginView
...
path('', CustomLoginView.as_view(),name='home'),
I accompanied the inclusion of the above path entry with this code in my views.py:
class CustomLoginView(LoginView):
#template_name = 'registration/login.html'
fields = '__all__'
redirect_authenticated_user = True
# def get_success_url(self):
# return reverse_lazy('/')
As you can see above, there are some lines which are commented out. I have tried running my server with those lines commented in and commented out. No dice.
It’s also worth pointing out that at the top of my views.py
I included: from django.contrib.auth.mixins import LoginRequiredMixin
and also added LoginRequiredMixin
as an argument inside every single CBV, like in this code snippet:
class InductionDetailView(DetailView, LoginRequiredMixin):
model = Induction
context_object_name = 'inductions'
I did that for all the other models.
I created these (non-Admin) credentials for web visitor to test but given that Chrome shows it is a non-secure site, CSRF token mechanism kicks in, preventing you from continuing. But I thought I would include this anyway just in case:
- Username: superdave
- Password: osbourne12
https://8ff1-2607-fea8-87e3-3200-00-a0f5.ngrok.io/accounts/logout/
https://8ff1-2607-fea8-87e3-3200-00-a0f5.ngrok.io/accounts/login/
My code base:
hypnos_juicer/urls.py (project level urls):
from django.contrib import admin
from django.urls import path, include
# from contents.views import CustomLoginView
urlpatterns = [
path('admin/', admin.site.urls),
# path('', CustomLoginView.as_view(),name='home'),
path('accounts/',include('django.contrib.auth.urls')),
path('', include('contents.urls')),
# path('classroom/', include('classroom.urls')),
]
contents/urls.py (app urls):
from django.urls import path, include
from .views import ContentListView, InductionDetailView,ResearchDetailView, PreambleDetailView, ScriptSuggestionDetailView,StockScriptDetailView, index
app_name = 'contents'
urlpatterns = [
path('', ContentListView.as_view(),name='home'),
path('preambling/<str:slug>', PreambleDetailView.as_view(),name='preamble_details'),
path('inductioning/<str:slug>', InductionDetailView.as_view(),name='induction_details'),
path('scripting/<str:slug>', ScriptSuggestionDetailView.as_view(),name='scriptsuggestion_detail'),
path('stock_scripting/<str:slug>', StockScriptDetailView.as_view(),name='stockscript_detail'),
path('researching/<str:slug>', ResearchDetailView.as_view(),name='research_detail'),
]
views.py (app):
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import ListView,DetailView
from .models import Preamble, Induction, Research, ScriptSuggestion,StockScript,Content
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView
from django.contrib.auth.decorators import login_required
''' class CustomLoginView(LoginView):
#template_name = 'registration/login.html'
fields = '__all__'
redirect_authenticated_user = True
#def get_success_url(self):
# return reverse_lazy('/')
'''
def index(request):
return render(request,'contents/index.html')
class ContentListView(ListView, LoginRequiredMixin):
# model_list.html
# model = Induction
model = Content
# template_name = 'home.html'
# fields =['author','title',]
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(ContentListView, self).get_context_data(**kwargs)
# Add in a QuerySet of all the Baklawa
context['inductions'] = Induction.objects.all()
context['preambles'] = Preamble.objects.all()
context['research'] = Research.objects.all()
context['scriptsuggestions'] = ScriptSuggestion.objects.all()
context['stockscripts'] = StockScript.objects.all()
return context
class PreambleDetailView(DetailView, LoginRequiredMixin):
model = Preamble
context_object_name = 'preambles'
class InductionDetailView(DetailView, LoginRequiredMixin):
model = Induction
context_object_name = 'inductions'
class ScriptSuggestionDetailView(DetailView, LoginRequiredMixin):
model = ScriptSuggestion
context_object_name = 'scriptsuggestions'
class StockScriptDetailView(DetailView, LoginRequiredMixin):
model = StockScript
context_object_name = 'stockscripts'
class ResearchDetailView(DetailView, LoginRequiredMixin):
model = Research
context_object_name = 'research'
models.py (app):
from django.db import models
class Content(models.Model):
pass
# Create your models here.
class Preamble(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=30,blank=True)
slug = models.SlugField(unique=True,blank=True)
# posting_date = models.DateField(auto_now=False, auto_now_add=False, **options), https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.DateField
def __str__(self):
return f'{self.title}'
class Induction(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=30,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
class ScriptSuggestion(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=300,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
class Research(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=300,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
class StockScript(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=300,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
models.py:
from django.db import models
class Content(models.Model):
pass
# Create your models here.
class Preamble(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=30,blank=True)
slug = models.SlugField(unique=True,blank=True)
# posting_date = models.DateField(auto_now=False, auto_now_add=False, **options), https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.DateField
def __str__(self):
return f'{self.title}'
class Induction(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=30,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
class ScriptSuggestion(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=300,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
class Research(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=300,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
class StockScript(models.Model):
title = models.CharField(max_length=300,blank=True)
body = models.TextField(max_length=300000,blank=True)
author = models.CharField(max_length=300,blank=True)
slug = models.SlugField(unique=True,blank=True)
def __str__(self):
return f'{self.title}'
Resources I have used so far: