How to escape '/' in django urls - django

I am working on a project that generates dynamic urls
for eg if you type mysite.com/<yourtexthere> The site should generate a url with mysite.com/yourtexthere (where yourtext here is a slug of a model)and I am able to do that but the problem arises when I put something like this mysite.com/yourtexthere/moretext, Django doesn't match it with any of my existing URL patterns and gives me 404.
I wanted to ask is there a way by which I can treat '/' as just another character and generate unique url mymysite.com/yourtexthere/moretext where yourtexthere/moretext is now the slug.
views.py
def textview(request, slug):
obj, created= Text.objects.get_or_create(slug=slug, defaults={'text':'', 'password':'123'})
return render(request, 'text/textpage.html', {'obj' : obj, 'created' : created})
urls.py
# Only patterns
urlpatterns = [
path('', home, name='home'),
path('<slug:slug>/', textview, name='textview'),
]

From Django models docs:
A slug is a short label for something, containing only letters, numbers, underscores or hyphens.
So the 404 is actually correct, maybe use another field.

Django path converters match strings in the input URL using regex.
The default path converters are pretty basic - source code.
The slugConverter matches any string that only contains characters, numbers, and dashes, not forward slashes. In string yourtexthere/moretext the largest substring it will match is yourtexthere.
The pathConverter matches a string containing any type of character, so the result can contain a forward slash. It will match all of yourtexthere/moretext. So change your urlpatterns to this:
# Only patterns
urlpatterns = [
path('', home, name='home'),
path('<path:slug>/', textview, name='textview'),
]
The pathConverter will match all special characters. If you don't want this you can create your own custom converter with a regex tailored to your needs. For example, you could simply extend the slugConverter to also match strings with forward slashes.
class SlugPathConverter(StringConverter):
regex = '[-a-zA-Z0-9_/]+'

Related

In Django, using urlpatterns, how do I match a url-encoded slash character as part of a parameter?

In my Django app I have these urlpatterns:
urlpatterns = [
url(r'^$', schema_view, name='swagger'),
url(r'^(?P<page_title>.+)/(?P<rev_id>[0-9]+)/$',
WhoColorApiView.as_view(), name='wc_page_title_rev_id'),
url(r'^(?P<page_title>.+)/$',
WhoColorApiView.as_view(), name='wc_page_title'),
]
The second entry will match a path like /en/whocolor/v1.0.0-beta/my_book_title/1108730659/?origin=* and the third will match a path like /en/whocolor/v1.0.0-beta/my_book_title/?origin=*.
The idea is that it's matching a page_title parameter (a Wikipedia article title), and an optional integer rev_id (revision id) parameter.
However, it does not work as intended for an article titled "Post-9/11", with path /en/whocolor/v1.0.0-beta/Post-9%2f11/?origin=*. I want this not to match the second pattern (which gets matched as page_title "Post-9" and rev_id 11), and instead match the third pattern.
I understand why the second pattern should match if the path is /en/whocolor/v1.0.0-beta/Post-9/11/?origin=*, but when the title is url-encoded as "Post-9%2f11" it still matches the second pattern instead of continuing on to the third pattern.
How can I make Django treat the url-encoded slash as part of the parameter instead of a path separator?
In Django there's something called Path Converters.
One of the existing path converters deals with things with slashes
path - Matches any non-empty string, including the path separator, '/'. This allows you to match against a complete URL path rather than a segment of a URL path as with str.
path('<path:page_title>/',
views.post_detail,
name='post_detail'),
When one uses path one doesn't need to escape anything, and it'll work. There are various cases similar to OP's where Path was used as a solution, such as:
Example 1
Example 2
Example 3
Example 4
Example 5
As Ivan Starostin mentions in a comment, OP should actually use the path converter slug.
According to the docs
A slug is a short label for something, containing only letters, numbers, underscores or hyphens.
For example, building-your-1st-django-site.
To do so, it's advisable that OP uses, in the model, a field of type SlugField.
slug = models.SlugField(max_length=250)
Then in the urls.py
path('<slug:post>/',
views.post_detail,
name='post_detail'),

Why is my django url regex not working

I want my url to accept 0 or more digits(positive or negative integers), I mean it should match '/','/0',...,'/9' as well as '/-9','/-88' etc.
This is the regex I am using ^([-]?[0-9]*)/$ . It works for all urls except '/', what is the problem with this regex?
EDIT:
This is my urlpatterns in urls.py in project directory:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'',include('basecalendar.urls'), name='date'),
]
and this is urlpattern for basecalendar
urlpatterns=[
url(r'^([-]?[0-9]*)/$',views.get_date),
]
Since you are working with urls you might want to make sure that you are ending your url with '/'. Also, the reason why this is not working because your url is expecting a '/' at the end. So a url something/ does not match your regex, rather something// does. All these observations are being made according to your regex. Usually to handle such conditions you should add one more url above your previous regex, something like:
url(r'^something/$', view),
url(r'^something/([-]?[0-9]*)/$', view),

Django url - No reverse match

Okay, to be clear I've searched and read, followed the official docs, tried multiple solutions from SOF, nothing seems to be working so I have to resort to shamefully asking for help.
I'm simply trying to generate urls the proper way.
root urls.py:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'|/', include('main.urls')),
]
urls.py:
app_name = 'main'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^vieworder/(?P<order_id>[0-9]+)/$', views.vieworder, name='vieworder'),
]
template file:
<td>View</td>
also tried:
<td>View</td>
Error:
Reverse for 'vieworder' with arguments '(1,)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['|/vieworder/(?P<order_id>d+)/$']
I don't understand why this is not working. I tested the regex against vieworder/1/ in a regex tester and it works fine. Django even tells me in the error that it tried the correct url pattern, however the error really isn't very clear on what is actually wrong.
Django is not able to reverse the use of a | character outside of a capturing group. However, I highly doubt you need it here.
Django always matches the first slash of the url, so there's no need to match the starting slash in your regex. Adding a starting slash would only match a second slash at the start of your url. Unless you want the url path to be example.com//vieworder/1/ rather than example.com/vieworder/1/, you should just remove the slash from your pattern.
Since the first slash is already matched by Django, and there's nothing else between the first slash and the vieworder/1/ part, you can just leave the include pattern empty:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('main.urls')),
]
This will match the url example.com/vieworder/1/, and allow Django to reverse the url.
As for your second problem:
You need to make the outer group a non-capturing group with ?::
url(r'^vieworder(?:/(?P<order_id>\d+))*/$', views.vieworder, name='vieworder'),
Django will substitute the outermost capturing group, which in this case should contain /1 instead of 1. By making it a non-capturing group, Django will substitute the argument 1 into the inner group instead of the outer group.

Only one letter of string is being passed to Django views function from template

HTML form:
<form id="save_form" method="post" action="{% url 'project_save' usernames=username project_name='lion' %}">
Notice the arg 'project_name's value is 'lion'
views.py:
def projectz_save(request, usernames, project_name):
template = loader.get_template('project_view/index.html')
context = RequestContext(request, {"username": usernames, "project": project_name})
return HttpResponse(template.render(context))
urls.py:
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^(?P<usernames>\w+)(?P<project_name>\w+)save$', views.projectz_save, name='project_save'),
)
What happens is that only the 'n' in 'lion' is being passed as an argument. When I re-render the page, the template variable "project" now has the value 'n' instead of 'lion.' Any idea why this is happening?
It happens if I use a variable instead of a string (which is obviously the ultimate goal), but even simplified down to a simple string it's still happening.
Your problem is that while the template is correctly constructing the URL, your urls.py regexp is too greedy.
Specifically, you have no divider between your usernames named group and your project name named group:
r'^(?P<usernames>\w+)(?P<project_name>\w+)save$'
Given any sequence of word characters, all but the last will be matched by the \w+ in the usernames group. The last will be matched by the project_name group, because + requires at least one character. So if username in the template is 'johndoe', the url tag will construct the URL:
johndoelionsave
The regexp will then match johndoelio as the usernames group, since all of those are matched by \w+, n as the project_name group, since it's matched by \w+, and then the fixed save and end-of-string parts.
Your best fix will be to break up the URL pattern so that the parsing is unambiguous. I suggest:
r'^(?P<usernames>\w+)/(?P<project_name>\w+)/save$'
In which case the template tag will produce:
johndoe/lion/save
and the regexp will parse out the details you want.

django urls regular expressions

So i have a main urls.py that looks like this:
urlpatterns = patterns('',
(r'^users/(?P<username>.*)/', include('app.urls')),
url(r'^users/(?P<username>.*)$',direct_to_template,{'template':'accounts/profile.html'}, name='profile'),)
and a app.urls.py
urlpatterns = patterns('',url(r'^app/create/$', create_city ,name='create_city'),)
my problem is, when i localhost:8000/users/michael/app/create/ it doesn't call my view. I have tried changing the order of the urls with no luck so i believe my problem is with the regular expressions but with no idea on what to change, anyone?
The named group (?P<username>.*) will match any characters, zero or more times. in your username, including forward slashes.
In url patterns, it would be more common to use (?P<username>[-\w]+). This would match at least one character from the set of lowercase a-z, uppercase A-Z, digits 0-9 hyphens and underscores.
I also recommend that you add a trailing slash to your pattern for your profile view.
Putting it all together, I suggest you use the following as a starting point for your urls.py:
urlpatterns = patterns('',
url(r'^users/(?P<username>[-\w]+)/$',direct_to_template, {'template':'accounts/profile.html'}, name='profile'),
(r'^users/(?P<username>[-\w]+)/', include('app.urls')),
)