Building published/unpublished feature for blog CMS

Hello Pythonistas!

I’m trying to write a basic “is_published” switch feature for posting content for the rudimentary Django CMS blog I am building. I’m trying to enable a user to flip the switch in the Admin Dashboard to turn a blog post from being accessible or inaccessible on the website. I’m using CBVs. My best attempt at crafing my DetailView can be found below, along with the template and the relevant snippet from my model.

In terms of behavior, currently whether the is_published switch is turned on or off in the Admin Dashboard, Django is serving the template, but the title, author, or body data point content are empty. It’s just a blank page in both cases. What I am trying to do is have Django serve a 404 when is_published is turned False and have Django serve the template and data text content when trned True. What is interesting is that when I comment out the get_context_data class method override, Django serves the text data successfully.

Any idea what I am doing wrong?

To come with the below, I leveraged this specific passage from the Django Docs on DetailViews: Generic display views | Django documentation | Django

What might you people recommend I try next?

class PreambleDetailView(LoginRequiredMixin,DetailView):
    model = Preamble
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        try:
            context['preambles'] = Preamble.objects.filter(is_published=True)
        except Preamble.DoesNotExist:
            raise Http404('Article does not exist!')
        return context
    
    context_object_name = 'preambles'

Here is my template:

{% extends 'base.html' %}

{% block content %}

<div class="body">
        
    {% if preambles  %}
        <h1 class="title">{{preambles.title}}</h1>
        <!-- <h3><em>Preamble</em></h3> -->
        <div class="author">Author: {{preambles.author}}</div>
        <div class="detail">{{preambles.body|safe}}</div> <!-- end detail class -->
    {% endif %}

</div> <!-- end body -->

{% endblock %}

Here is my models.py:

from django.db import models

class GatewayProtect(models.Model):
    is_protected = models.BooleanField(default=True)
    
class Content(models.Model):
    pass

class Preamble(models.Model):
    title = models.CharField(max_length=300,blank=True)
    is_published = models.BooleanField(default=True)
    author = models.CharField(max_length=30,blank=True)
    slug = models.SlugField(unique=True,blank=True)
    body = models.TextField(max_length=300000,blank=True)

A DetailView accepts the pk parameter to select a single instance of the referenced model (Preamble). You then have access to that object as self.object and self.preamble.

In your get_context_data, you’re going to retrieve all Preamble objects where is_published == True. It does not apply this to the instance of the object automatically retrieved. Also, you’re overriding your class definition of context_object_name by reusing preambles in this method, which is preventing the template from working.

Side note: That filter will never throw a DoesNotExist exception. Filters will return empty querysets.

What you more likely want to override is get_object. You can call super in your get_object method to get the object, then check the is_published attribute to determine whether you want to display that object.

And get rid of the get_context_data method.