kauii8
kauii8

Reputation: 229

How to edit output in Django ListView before passing to template

So I have a Django ListView that looks like

class FirePageView(ListView):
    model = MyModel
    template_name = 'page.html'
    context_object_name = 'my_list'
    ordering = ['-timestamp']

So can I render a table just fine and everything is working there. However, I want to apply a transformation, for example changing all the timestamps from UTC to EST before sending it to the template. This way the template shows the times in EST but not UTC. How can I edit what the ListView passes into the template?

Upvotes: 0

Views: 650

Answers (2)

kauii8
kauii8

Reputation: 229

Thanks for your comments and answers everyone. If you are interested in directly editing the queryset which is probably useful in it's own right please take a look below at @Yves Hary's answer.

For my usecase, a custom template tag (https://docs.djangoproject.com/en/3.1/howto/custom-template-tags/#writing-custom-template-filters) works. If you are interested this is my code:

In app/templatetags/timezone_conversion.py

import pytz

from django import template

register = template.Library()

@register.filter(name='timezone_conversion_filter')
def timezone_conversion_filter(time, timezone):
    tz = pytz.timezone(timezone)
    print(time, tz, )
    local_dt = time.astimezone(tz)
    print(time, tz)

    return local_dt.strftime("%b %e, %Y, %I:%M %p")

Then in your html page

{% load timezone_conversion %}

{{ your_datetime|timezone_conversion_filter:"US/Pacific" }}

Upvotes: 0

Yves Hary
Yves Hary

Reputation: 312

Like the other authors said, your specific use case (transforming timestamps) would be solved best by a template tag.

If you still want to modify your data, have a look into djangos MultipleObjectMixin which gets used in djangos ListView:

class MultipleObjectMixin(ContextMixin):
    """A mixin for views manipulating multiple objects."""
    allow_empty = True
    queryset = None
    model = None
    paginate_by = None
    paginate_orphans = 0
    context_object_name = None
    paginator_class = Paginator
    page_kwarg = 'page'
    ordering = None

    def get_queryset(self): # YOU CAN OVERRIDE THIS METHOD FOR YOUR USE
        """
        Return the list of items for this view.

        The return value must be an iterable and may be an instance of
        `QuerySet` in which case `QuerySet` specific behavior will be enabled.
        """
        if self.queryset is not None:
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                queryset = queryset.all()
        elif self.model is not None:
            queryset = self.model._default_manager.all()
        else:
            raise ImproperlyConfigured(
                "%(cls)s is missing a QuerySet. Define "
                "%(cls)s.model, %(cls)s.queryset, or override "
                "%(cls)s.get_queryset()." % {
                    'cls': self.__class__.__name__
                }
            )
        ordering = self.get_ordering()
        if ordering:
            if isinstance(ordering, str):
                ordering = (ordering,)
            queryset = queryset.order_by(*ordering)

        return queryset

You can hook into the get_queryset() method and return an iterable which is transformed the way you want it. With using this hook you can still use all benefits of the generic ListView.

Upvotes: 2

Related Questions