Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22462

Experienced Django: KidTasks: Simple Class Based Views

$
0
0

For this post I’ve taken some advice from a python talk I watched a few weeks ago and converted some of my function-based-views (FBV) to class-based-views (CBV).  I found this simple and very cool for my simplest view and a bit more complex for another view.  I’ll look at each of these in turn.

Index View

The first view I changed was the simplest.  It merely took a single data type and sent it to a template.

The FBV version of this looked like:

def index(request):
    """ Shows all of the tasks in the system, broken down by kid """    kids = get_list_or_404(Kid)
    return render(request, 'tasks/index.html', {'kids': kids})

It’s not much of a surprise to see that a simple FBV turns into an even simpler CBV.  Here’s how that ended up:

class FullList(ListView):
    """ Shows all of the tasks in the system, broken down by kid """    model = Kid

Note that this change required that I move the template “index.html” to kid_list.html.  I also could have specified a template_name in the class, but this seemed like a good time to clean it up.

Today view

The transformation for this view was less pretty.  After a bunch of messing around and reading different examples, I came up with the solution below.  In general it seems the ListView is fantastic at representing a specific model as it exists in the database.  My issue was the need to update the “today” list if needed to match the tasks for the current day and then return only that.

I’ll show what the change looked like and hold off my concerns and ideas until afterward.

Here’s where we started:

def today(request):
    """ Generate the 'today' page showing which tasks are due today """    day_name = datetime.datetime.now().strftime("%A")
    kid_list = get_list_or_404(Kid)

    kids = dict()
    for kid in kid_list:
        tasks = build_today(kid)
        if tasks:
            kids[kid.name] = tasks
    return render(request, 'tasks/today.html', {'kids': kids, 'day': day_name})

From which we ended up here:

class TodayList(ListView):
    """ Generate the 'today' page showing which tasks are due today """    model = Kid
    template_name = 'tasks/today.html'

    def get_context_data(self, **kwargs):
        # get_context_data creates the context
        context = ListView.get_context_data(self, **kwargs)

        day_name = datetime.datetime.now().strftime("%A")
        kid_list = get_list_or_404(Kid.objects.order_by('name'))

        kids = {kid.name: kid.build_today() for kid in kid_list}
        context.update({'kids': kids, 'day': day_name})

        return context

It’s about the same amount of code, but somehow feels less ‘obvious’.  It relies on hooking the CBV pretty late in the processing and substituting the newly created kids dict into the context.  The template for this ONLY uses that part of the context which means that technically I could forego the call to the superclass (I think) and just return the kids dict.

I have two thoughts on how this could be done better.  The first is to split the work here.  I could hook the processing earlier to ensure that the today task is updated and stored in the kid and then modify the template to take the full list of kids, running through them to display the today list for each.  If I were to stay with this overall design, I think I’d go this direction.

However, my other thought is to re-design the models (again) to more closely match what’s happening here.  As I write this, I am also working on adding FormViews to allow easier addition of tasks for a given day.  That will likely result in a model redesign, so I suspect this part will change anyway.

The code for this point in the project is stored in branch blog/04-SimpleCBV.

Thanks for following along!


Viewing all articles
Browse latest Browse all 22462

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>