Django: Parameters in URLs .... which start with a slash - django

I use a regex for URL dispatching like described in the Django docs.
r'^remote/(?P<slug>[^/]+)/call_rfc/(?P<rfc_name>.+)$'
Unfortunately rfc_name can start with a slash!
Example:
https://example.com/remote/my_slug/call_rfc//MLK/FOO
The rfc_name is /MLK/FOO.
But this fails. Somewhere (I don't know yet if it is in the browser or in Django) the duplicate slash gets removed.
What is the best practice to handle URL parameters which can start with a slash?

It almost seems that you can consider the latest "slug" as a path. If that's the case, in your URL definition you can use path to represent that. You can have a look here to check if it helps.
path('remote/<slug:slug>/call_rfc/<path:rfc_name>', yourviewhere)
Or, you can perhaps write your custom path converter.

Related

Django catch-all URL without breaking APPEND_SLASH

I have an entry in my urls.py that acts as a catch-all which loads a simple view if it finds an appropriate page in the database. The problem with this approach is that the URL solver will then never fail, meaning that the APPEND_SLASH functionality won't kick in - which I need.
I'd rather not have to resort to adding a prefix to the static page URLs to stop it being a catch-all. I do know about flatpages, which uses a 404 hook rather than an entry in urls.py, and I had kinda hoped to avoid having to use it, but I guess this problem might be exactly the kind of reason why one would use it.
Any way round this problem or should I just give in and use flatpages?
Make sure that your catch-all URL pattern has a slash at the end, and that the pattern is the last in your URLconf. If the catch-all pattern doesn't end with a slash, then it will match stray URLs before the middleware tries appending a slash.
For example, use r'^.*/$' instead of r'^.*' as your last pattern.
To do the same, but pass the url to the view as a named argument, use r'^(?P<url>.*)/$'.
The statement if it finds an appropriate static page in the database seems like your static pages are not quite static so, you either pass your links through urls.py (just like you do now), or you extract those pages from the DB, put them in a directory and configure that directory as one for serving static files

Django's Satchmo and flatpages issue

I'm having a problem with configuring Flatpages in Satchmo. I've used them before, in a pure django app, but now it just doesn't work, returning 301 http error when I'm trying to enter a flatpage-configured site.
What I've done to configure it:
added the middleware "django.contrib.flatpages.middleware.FlatpageFallbackMiddleware" to MIDDLEWARE_CLASSES as last in the list,
configured example pages in admin module.
Simply what the docs say about flatpages config.
I'm feeling helpless. Don't know how could I debug this issue. Any thoughts on that?
And of course help appreciated.
Thanks to suggestion by Peter I've managed to narrow the problem to my urls.py file, for the satchmo shop.
The urlpatterns has only one entry:
(r'', 'django.views.generic.simple.redirect_to', {'url' : '/shop/'}),
This version does not work and moreover interfere with flatpages. But disabling flatpages from MIDDLEWARE_CLASSES and adding it to urls.py like the snippet below works:
(r'^(?P<url>.*)$', 'django.contrib.flatpages.views.flatpage'),
(r'', 'django.views.generic.simple.redirect_to', {'url' : '/shop/'}),
However next problem is with the redirection from / to /shop/. With the above config it results in infinite loop.
Perhaps you know the reason for that behavior (redirect overriding flatpage) and maybe You could suggest some working solution to this problem or what should be done with requests to /.
It returns 301? That's Page Moved Permanently (HttpResponsePermanentRedirect) and there are no references to that in the flatpages directory so I don't think it's coming from there. In fact there are only about 5 references to HttpResponsePermanentRedirect in all of the standard 1.1.1 release.
Possible approaches:
Comment out the FlatPages middleware and see if the error changes (I'm betting it won't).
Try changing the order of your MIDDLEWARE classes and see if things change.
When presenting a problem like this it's better to get very specific by showing the exact code from applicable portions of settings.py (or whatever) and by giving other things like precise URLs and the urls.py patterns you are trying to match.
Update:
OK, some random thoughts:
The pattern (r'^(?P<url>.*)$', 'django.contrib.flatpages.views.flatpage'), will match anything. Any patterns after it will never be seen.
flatpages doesn't work by being called directly, it does its magic in middleware. It looks for 404 responses (Page Not Found) and then looks to see if that path exists in its table. If so, it calls a view that renders the page, etc. etc. If it doesn't find a match it let's the 404 continue on through middleware processing.
The pattern (r'', 'django.views.generic.simple.redirect_to', {'url' : '/shop/'}), will match anything (I just tested it). If you want to match an empty path, use r('^$', etc.). This is the source of your infinite loop.
If you are new to regular expressions the Django urls.py file can seem like F*cking Magic. I recommend starting very simply and add one rule at a time. Do some quick tests to ensure that the new rule a) matches stuff you want it to match, and b) doesn't match stuff it shouldn't. In particular, make sure that some of the rules that occur later in the file are still reachable. In this case they wouldn't have been which should have raised a red flag.

Django url tag gives wrong values

My URLconf has:
url(r'^view-item$', 'appname.views.view_item', name='view-item'),
Now, if I go to http://myhost/path_to_django_app/view-item/, it works. However, {% url view-item %} returns '/view-item/'. Why is it doing this?
This problem occurred when I moved the application to a new server, so I'm guessing something must be configured wrong, but I don't even know where to look.
This may be due to the SCRIPT_NAME variable not being set correctly. The url tag will use this variable to compose the final absolute path to return.
You should check what request.META['SCRIPT_NAME'] is set to in one of your views. If it is not set correctly, then you may need to look into your backend configuration. If you are using mod_python, this usually involves making sure that django.root is set in the apache config. Check the installation docs for more info.
If you still can't get it to work, you can try adding this to settings.py:
FORCE_SCRIPT_NAME = '/path_to_django_app/'
The usual way to write your URl in django is with a trailing '/':
url(r'^view-item/$', 'appname.views.view_item', name='view-item')
or:
url(r'^view-item/', include('view.urls')),
Life will be much easier if you follow this convention.

Recursive URL Patterns CMS Style

Whenever I learn a new language/framework, I always make a content management system...
I'm learning Python & Django and I'm stuck with making a URL pattern that will pick the right page.
For example, for a single-level URL pattern, I have:
url(r'^(?P<segment>[-\w]+)/$', views.page_by_slug, name='pg_slug'),
Which works great for urls like:
http://localhost:8000/page/
Now, I'm not sure if I can get Django's URL system to bring back a list of slugs ala:
http://localhost:8000/parent/child/grandchild/
would return parent, child, grandchild.
So is this something that Django does already? Or do I modify my original URL pattern to allow slashes and extract the URL data there?
Thanks for the help in advance.
That's because your regular expression does not allow middle '/' characters. Recursive definition of url segments pattern may be possible, but anyway it would be passed as a chunk to your view function.
Try this
url(r'^(?P<segments>[-/\w]+)/$', views.page_by_slug, name='pg_slug'),
and split segments argument passed to page_by_slug() by '/', then you will get ['parent', 'child', 'grandchild']. I'm not sure how you've organized the page model, but if it is not much sophiscated, consider using or improving flatpages package that is already included in Django.
Note that if you have other kind of urls that does not indicate user-generated pages but system's own pages, you should put them before the pattern you listed because Django's url matching mechanism follows the given order.

How do I add a prefix to all urls and generically parse that as a kwarg

Let's say I have a site where all urls are username specific.
For example /username1/points/list is a list of that user's points.
How do I grab the /username1/ portion of the url from all urls and add it as a kwarg for all views?
Alternatively, it would be great to grab the /username1/ portion and append that to the request as request.view_user.
You might consider attacking this with middlware. Specifically using process_request. This is called before the urlresolver is called and you can do pretty much anything to the request (request.path in this case) you want to. You might strip out the username and store it in the request object. Specifics depend (obviously) on the conditions under which you do/do not want to remove the first path component.
Updated for comment:
Whichever way you go about it, when you call reverse() you have to give it the additional context info -- it can't just automagically figure it out for itself. Django doesn't play any man-behind-the-curtains games -- everything is straight Python and there isn't any global state floating around just off stage. I think this is a Good Thing™.