Search code examples
djangodjango-modelsdjango-flatpages

Publish a custom Django Flatpage at a set date and time


I have a custom Flatpage model:

from django.contrib.flatpages.models import FlatPage

class MyFlatPage(FlatPage):

    publish = models.DateTimeField()

so that I can add a publish date in the future.

Now, I don't have a proper list of flatpages on the front end, my use for frontpages is more like 'one-offs', where I specific the URL and all that. For example, 'about', '2019prize', 'Today's walk', stuff like that.

The urls.py is set up to catch all the flatpages with:

from django.contrib.flatpages import views
re_path(r'^(?P<url>.*/)$', views.flatpage)

How can I set these pages I create to be displayed only after the publish date has arrived? I know that I can filter them by looking up something like pages.filter(publish__lte=now). Where and how should I put that code though?

Additional information

I suppose I need to create a custom view, is that correct? The original view is in ../lib/python3.8/site-packages/django/contrib/flatpages/views.py:

def flatpage(request, url)
    if not url.startswith('/'):
        url = '/' + url
    site_id = get_current_site(request).id
    try:
        f = get_object_or_404(FlatPage, url=url, sites=site_id)
    except Http404:
        if not url.endswith('/') and settings.APPEND_SLASH:
            url += '/'
            f = get_object_or_404(FlatPage, url=url, sites=site_id)
            return HttpResponsePermanentRedirect('%s/' % request.path)
        else:
            raise
    return render_flatpage(request, f)

@csrf_protect
def render_flatpage(request, f):

    if f.registration_required and not request.user.is_authenticated:
        from django.contrib.auth.views import redirect_to_login
        return redirect_to_login(request.path)
    if f.template_name:
        template = loader.select_template((f.template_name, DEFAULT_TEMPLATE))
    else:
        template = loader.get_template(DEFAULT_TEMPLATE)

    f.title = mark_safe(f.title)
    f.content = mark_safe(f.content)

    return HttpResponse(template.render({'flatpage': f}, request))

How can I extend this, adding my if publish__lte=now code?


Solution

  • What I did is copy-paste the view code from ../lib/python3.8/site-packages/django/contrib/flatpages/views.py to my app.views, rename the two functions, and add the following to render_myflatpage:

    def render_myflatpage(request, f):
    [...]
    
        if f.publish > now:
            f.content = 'This content will be published on ' + str(f.publish)
    

    I then assigned the new view in the catch-all urls.py code:

        re_path(r'^(?P<url>.*/)$', myflatpage)
    

    I know this goes against the DRY protocol; this works for me for the time being. If there's a more elegant solution please do let me know.