meeb / django-distill

Minimal configuration static site generator for Django
MIT License
441 stars 35 forks source link

Cannot reverse namespaced urls #86

Closed dhoulder closed 8 months ago

dhoulder commented 8 months ago

Can namespaced urls be reversed in django-distill? Please see below.

urls.py:

from django_distill import distill_path
from ..views import SearchView

class StaticSearchView(SearchView):
    search_results_url = 'static_site:search_results'

app_name = 'static_site'

urlpatterns = (
       distill_path(r'_search',
                    StaticSearchView.as_view(),
                    name='search_results',
                    distill_func = lambda: None),
)

views.py:

class SearchView(TemplateView):
    template_name = 'photo_cms/search.html'

photo_cms/search.html:

...
<form id="site-search-form" role="search" aria-label="Site"
            action="{% url view.search_results_url %}">
...

When I run it I get this:

(ve) david@blackbox:photo_cms$ python manage.py distill-local -v 3  --exclude-staticfiles ~/JUNK/static_site
...

Generating static site into directory: /home/david/JUNK/static_site
Loading site URLs
CommandError: Failed to render view "/_search": 'static_site' is not a registered namespace
(ve) david@blackbox:photo_cms$ 

It works fine if I don't use namespaced urls. urls.py:

class StaticSearchView(SearchView):
    search_results_url = 'static_site_search_results'

urlpatterns = (
       distill_path(r'_search',
                    StaticSearchView.as_view(),
                    name='static_site_search_results',
                    distill_func = lambda: None),
)
(ve) david@blackbox:photo_cms$ python manage.py distill-local -v 3  --exclude-staticfiles ~/JUNK/static_site
...
Generating static site into directory: /home/david/JUNK/static_site
Loading site URLs
Rendering page: /_search -> /home/david/JUNK/static_site/_search ["text/html; charset=utf-8", 12522 bytes] 

Any thoughts? Thanks

meeb commented 8 months ago

Yes, django-distill supports namespaced apps and URLs. The error you're getting here of 'static_site' is not a registered namespace is from Django, it's just from a generic catch-all with django-distill so it's not Distill raising this:

https://github.com/meeb/django-distill/blob/master/django_distill/renderer.py#L296

There's examples of namespaced app usage in the tests:

https://github.com/meeb/django-distill/blob/master/tests/namespaced_urls.py

And sub-namespaced apps:

https://github.com/meeb/django-distill/blob/master/tests/namespaced_sub_urls.py

And the parent urls.py that loads them:

https://github.com/meeb/django-distill/blob/master/tests/urls.py#L104

There are a few things I've never done with your example that might cause this. As my best guess I would suspect it's a missing namespace= kwarg in the parent urls.py, also detailed in the examples:

https://docs.djangoproject.com/en/5.0/topics/http/urls/#id5

When using namespaces does your _search URL work directly in a browser?

dhoulder commented 8 months ago

When using namespaces does your _search URL work directly in a browser?

Yes. In my live version of the site that I am trying to "distill" I have… urls.py:

app_name = 'photo_cms'

urlpatterns = [
    re_path(r'^_search$',
            SearchView.as_view(),
            name='search-results'),

The view class has a property

    search_results_url = 'photo_cms:search-results'

and the template fragment

<form id="site-search-form" role="search" aria-label="Site"
            action="{% url view.search_results_url %}">

renders as

<form id="site-search-form" role="search" aria-label="Site"
            action="/_search">

So, yes it all works fine as a normal dynamic django app.

The problem only arises when reversing a namespaced url, (using the namespace:url syntax), either via reverse() or the {% url ... %} template tag, under django_distill.

I don't think any of your tests exercise that. I'm basically following the polls/urls.py example from https://docs.djangoproject.com/en/5.0/topics/http/urls/#id5

As my best guess I would suspect it's a missing namespace= kwarg in the parent urls.py

I don't have a parent urls.py in this case. It's just one urls.py with app_name = ... and no includes.

dhoulder commented 8 months ago

Actually, on closer reading of https://docs.djangoproject.com/en/5.0/topics/http/urls/#url-namespaces-and-included-urlconfs it looks like app_name = .... may only be relevant when a urls.py is used via include(), and maybe not when it is used as a ROOT_URLCONF. I will experiment.

dhoulder commented 8 months ago

I've confirmed that app_name only works in an included urls.py, not in ROOT_URLCONF, so reversing a namespaced url works fine in django_distil. Sorry for the false alarm. I'll close this issue.

Thanks for writing django_distil. My hosting provider is withdrawing WSGI support from its shared hosting plans, so django_distil should get me out of trouble.

meeb commented 8 months ago

No problem, thanks for the confirmation. I had assumed you were using include()'d namespaces due to the app_name being present. I'm still not sure why an app_name in the root urls.py causes that error, but given it's pretty odd unless it becomes a common issue I probably won't spend any time on working out what part of the Django test framework is being tripped by that.

As a tip, you can use django-distill with GitHub pages or Cloudflare pages for totally free static hosting if you've not tried it already!

You OK if I close this issue?

dhoulder commented 8 months ago

Yep, closing it now. Thanks for all your effort!