Passing model variables to template view

Hi! I hope this is the right place to ask for help (looks like it from the pinned post).

I’m creating this “Announcement”/“System Message” feature for my webapp. I’ve created a model with a message, start, and end date variable and added an object in the admin panel.

I’ve been having problems passing the data to my templates. I wrote some test code as shown below (there is only one object):

 {% for obj in SysMessage %}
            <p>data</p>
            {% empty %}
            <p>no data</p>
            {% endfor %}

…and I get “no data” as the result.
This is the view function:

def index(request):
    template = loader.get_template('index.html')
    return HttpResponse(template.render({}, request), {"SysMessage":SysMessage.objects.all()})

Am I missing something? What am I doing wrong?

You should be passing the view context as an argument to template.render (in place of that empty dict), not as the second parameter to HttpResponse

Changed this… didn’t work.

Edit: This is how the code is now.

 return HttpResponse(template.render({"SysMessage":SysMessage.objects.all()}, request))

Hi JohnB2001,

I’m assuming you are duplicating the pattern for the view from the tutorial, specifically this section. The code for such is:

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))

If we look at what you have defined, we can see you’re passing the dict with SysMessage to the HttpResponse rather than to template.render.

What you should do instead is:

def index(request):
    template = loader.get_template('index.html')
    return HttpResponse(template.render({"SysMessage":SysMessage.objects.all()}, request))

However, the shortcut method django.shortcuts.render is very nice to use and can reduce some boilerplate code.

from django.shortcuts import render

def index(request):
    return render(request, 'index.html', {"SysMessage":SysMessage.objects.all()})

Let me know if there are any parts that you’d like further clarification on.

-Tim

@CodenameTim,
I followed that page and a Stack Overflow post
Changed it accordingly, the line is as shown in your post… however, it still is not working. I’m still getting a “no data” response.

As for the shortcuts… I missed that part. Thanks for the tip.

Hmm, if we know we’re rendering the queryset properly, then my next thought is that there is no data stored. Can you verify that there are SysMessage instances? You can check the admin, open a django shell (python manage.py shell), or print the queryset in the view then check the console. You can also use the Django Debug Toolbar’s Template Panel.

My admin page is showing this:

Cool, that’s good. Now we need to learn why those aren’t being rendered. There are a few points where this could fail:

  • The view that’s doing the rendering isn’t actually the function you’ve defined.
  • There’s a syntax problem in the template that’s causing it to not render what is wanted.

Again the Debug Toolbar is helpful for these type of debugging. You can also add some other values to the context that’s passed to the view to verify that’s working as expected. You can also try rendering {{ SysMessage }} directly in the template to see what the value of that is.

What you’re trying to discover is where the fault point is. The error is likely some configuration or a small typing mistake resulting in the application not working as expected. The way I approach debugging is to take every assumption, starting with those that are most likely to result in the error and then validate that assumption.

{{ SysMessage }} also shows up empty.

I have my suspicions I made a mistake somewhere…
As for the functions… that’s the only index view function in the project.

I also just installed the debug toolbar… Never used it before, but it seems pretty nifty.
If I’m understanding this part correctly… the brackets should not be empty.

The arguments and keyword argument columns are the args and kwargs passed to the view function. Since index only takes request, that would match. However, the part that doesn’t make sense is that the view function column indicates a TemplateView is the view handler. That’s a class based view, but in the code you’ve shared above you have a function based view defined. This implies that the request is being routed to another view rather than the one you expect. The issue is likely with your urls.py file(s).

Hmm…

I have two urls.py files…
One in the app already created in my project…I created this line to include the urls.py from the app that contains all my urls and views functions:

path('', include('mainsite.urls'))

Perhaps that might be it, or part of it? If I remove that line, the views are no longer displayed.

Or perhaps something in the urls.py from mainsite?

from django.urls import path

from . import views
from django.views.generic.base import TemplateView

urlpatterns = [
    #path('', views.index, name='index'),
    path(r'', TemplateView.as_view(template_name="index.html"), name="index"),
    path('home/', TemplateView.as_view(template_name="index.html"), name="index"),
...

(not the complete file)

I followed some tutorial or something somewhere, and that’s what I ended up doing. I feel like I can see where the issue might be.

The include line generally fine as long as you understand what it’s doing. I’d suggest revisiting the docs on include.

In mainsite/urls.py there are 2 or 3 paths named as index. The name attribute should be unique per namespace, or in your case within this file. If you aren’t using the TemplateView’s anymore, then you should remove them. That would clean up this problem for you if you only had the following defined:

urlpatterns = [
    path('', views.index, name='index'),
    path('home', views.index), # Not defining name will route requests to /home/, but prevents you from generating the URL via `reverse` or `{% url %}` 
]

Well, I marked your previous answer as a solution. That was the problem… fixed, and my feature works now.

I put the ‘/home’ view there in case someone decides to type it in the url bar I guess, but I might change or remove that URL pattern.

Now all I need to do with the feature is figure out how to check if the user’s date is in between the start date, and the expiration of the messages I add.

Thanks!