Use Escaped url in Django url regex mismatch - python

I'm trying to use an escaped url as a re_path variable for an object identifier in my API. The logic to connect the escaped url to an object is there, but I can't figure out why the regex is not matching.
In my head, a GET request with the following url /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo should be parsed into obj = 'http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1' and field = 'foo' for further processing. Ultimately, returning the object and 200. However I am getting a 404 with a very specific Django error that only proliferates when Django unfruitfully iterates through all the paths available.
<HttpResponseNotFound status_code=404, "text/html">
(Pdb) response.content
b'\n<!doctype html>\n<html lang="en">\n<head>\n <title>Not Found</title>\n</head>\n<body>\n <h1>Not Found</h1><p>The requested resource was not found on this server.</p>\n</body>\n</html>\n'
I know the path exists as when I examine the urlpatterns, the path is present:
(Pdb) pp object_router.get_urls()
[
...
<URLPattern '^(?P<obj>https?[-a-zA-Z0-9%._\+~#=]+)/(?P<field>foo|bar)\/?$' [name='test-detail-foobar']>
]
The url is escaped with urllib.parse.quote(obj.url, safe="")
Regexs tried:
r"https?[-a-zA-Z0-9%._+~#=]+"
r"https?[%23A](www\.)?[-a-zA-Z0-9#:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9#:%_\+.~#?&//=]*)(?=\/foo)" https://regexr.com/6ue7b
r"(https?://(www.)?)?[-a-zA-Z0-9#:%.+~#=]{2,256}(.[a-z]{2,6})?\b([-a-zA-Z0-9#:%+.~#?&//=]*)
Edit:
Based off the Django Path Convertor path regex, I've changed my regex to https?.+ with the compiled version as '(?P<obj>https?.+)/(?P<field>foo|bar)\\/?$'. This is moving in the right direction, however I've further identified some weirdness. Basically it seems that escaping the path variable url (obj) is partially to blame for the mismatch as an unescaped url (without query parameters) will return a differently handled API response. Further more, adding a query parameters/a question mark, once again returns us back to the Django 404.

Consider a simple project like this:
urls.py
from django.contrib import admin
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path(r"https?[-a-zA-Z0-9%._+~#=]+", views.test, name="test"),
path('admin/', admin.site.urls),
]
views.py
from django.http import HttpResponse
def test(request, obj, field):
print(f"The object is {obj}")
print(f"The field is {field}")
return HttpResponse("Test test")
When visiting the following URL: /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo
You get this error:
(I've outlined the relevant part with red.)
Django automatically decodes the encoded URL and only then applies the regex match. objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo becomes objects/http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1/foo. You will have to write the equivalent regex expression that matches against the decoded URL.
Something like this will work:
urls.py
from django.contrib import admin
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path(r"(?P<obj>https?:\/\/.*\?id=[\d\w-]+)\/(?P<field>foo|bar)", views.test, name="test"),
path('admin/', admin.site.urls),
]
views.py
from django.http import HttpResponse
def test(request, obj, field):
print(f"The object is {obj}")
print(f"The field is {field}")
return HttpResponse("Test test")
Visiting the URL /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo will print the following to the console:
The object is http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1
The field is foo

If I am understanding your issue properly, it looks like you are attempting to get a regex match and immediately send a request to the resultant url?
If that is the case, you are sending the request to an improperly formatted url. The first regex you posted looks like it works just fine to get the result you are asking for, however it results in a url that is still encoded.
You need to "unquote" the url prior to making the request.
import re
from urllib.parse import unquote
path = '/objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo'
resp = re.search("https?[-a-zA-Z0-9%._+~#=]+", path)
url = resp[0]
print(url)
print(unquote(url))
results in and output of:
http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1
http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1

Related

Avoid Django form being resubmitted by using HttpResponseRedirect

My views.py runs code fine when I press a button on my HTML page, views.py:
def start_or_end_fast(request):
#If starting fast, add a row to the db:
#fast_finished = False
#start_date_time using = current time
#end_date_time using = current time
if request.method == 'POST' and 'start_fast' in request.POST:
add_fast = logTimes(fast_finished=False,start_date_time=datetime.now(),end_date_time=datetime.now())
add_fast.save()
print(add_fast.start_date_time,add_fast.end_date_time)
print('Fast started')
#return render(request,'startandstoptimes/index.html')
return HttpResponseRedirect('startandstoptimes/index.html')
You can see my commented return line, this works but when I refresh the page I can resubmit the data, I want to avoid this. In researching my solution, I saw this could be solved using HttpResponseRedirect but I am not able to get this to work with my code, the more I change the more broken things become.
My application urls.py:
from turtle import home
from django.urls import path,include
from . import views
urlpatterns = [
path('', views.start_or_end_fast,name="start_or_end_fast")
]
My project urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('startandstoptimes.urls'))
]
I believe it is related to the URLs, due to the 404 message I see:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/startandstoptimes/index.html
Using the URLconf defined in myfastingsite.urls, Django tried these URL patterns, in this order:
admin/
[name='start_or_end_fast']
The current path, startandstoptimes/index.html, didn’t match any of these.
Am I going down the right route trying to use HttpResponseRedirect or is there a better solution?
class HttpResponseRedirect¶
The first argument to the constructor is required – the path to redirect to. This can be a fully qualified URL (e.g.
'https://www.yahoo.com/search/'), an absolute path with no domain
(e.g. '/search/'), or even a relative path (e.g. 'search/'). In that
last case, the client browser will reconstruct the full URL itself
according to the current path. See HttpResponse for other optional
constructor arguments. Note that this returns an HTTP status code 302.
See this link for more details: docs
As what the documentation says, HttpResponseRedirect accepts URL and not the path of your template. You should be doing it something like this:
from django.urls import reverse
return HttpResponseRedirect(reverse('start_or_end_fast'))

Get url variable and value into urlpatterns in Django

I was trying to get the variable and value of a url in urlpatterns in Django. I mean, I want to put in the address of the browser type: https://place.com/url=https://www.google.es/... to be able to make a translator. And be able to pick up the variable and value in the function that receives. At the moment I'm trying to get it with re_path like this:
from django.urls import path, re_path
from . import views
urlpatterns = [
path('', views.index),
re_path('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_#.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', views.index_traductor),
]
The regex match picks it up, but I don't know how to send it as a value in a variable to receive here:
from django.http import HttpResponse
def index(request):
return HttpResponse("flag")
def index_traductor(request, url=''):
return HttpResponse("%s" % url)
I get a blank page. Any ideas?
Uh, no need for regex - why not just use get parameters?
URL:
https://place.com/?param1=val1
views.py
def my_view_function(reuqest):
# unpack get parameters:
val1 = request.GET.get('param1')
# do something ...

How can I handle query "?" in my django urls.py

I am new to Django. I have to write a moke. My server will look at a specific address.
Like this:
portal/client_api.ashx?client=SAPRA&key=1234234&func=status&code=99999
I wrote:
urls.py
from django.conf.urls import patterns, url
from rt_moke import views
urlpatterns = patterns('',
url(r'code=(?P<code_id>\w+)/', views.Sapata, name='sapata'),
)
and views.py
from django.http import HttpResponse
status = {u"99999": u'{"code": "99999","status": "undelivered"}',\
u"88888": u'{"code": "88888","status": "delivered"}',\
}
def Sapata(request, code_id):
return HttpResponse(status[code_id])
When I request for portal/client_api.ashx?client=SAPRA&key=1234234&func=status&code=99999 without ? mark - it works, and with ?- not. I understand, that it is query string and Django skips it in the regexp. So what can I do?
This URL:
portal/client_api.ashx?client=SAPRA&key=1234234&func=status&code=99999
has two parts, the path:
portal/client_api.ashx
and the query string:
client=SAPRA&key=1234234&func=status&code=99999
which is parsed into request.GET.
In views.py you should get params from request (like simple dict in request.GET), for example:
def test(request):
code = request.GET.get('code') # here we try to get 'code' key, if not return None
...
and of course, we can't use GET params to parse URLs in urls.py. Your urls.py should looks like:
from django.conf.urls import patterns, url
from rt_moke import views
urlpatterns = patterns('',
url(r'^portal/client_api\.ashx$', views.Sapata, name='sapata'),
)
P.S. Please, don't use capital letters in names of functions.

Why is the first "hello world" example in the django book not working?

I am (trying) to learn Django for python 2.7 by follow the Django book, but am still stuck with the hello world example when trying to configure views.py and urls.py. I've basically copied everything line by line, but still get the same 404-error when I access the local test-server:
Request Method: GET
Request URL: http://127.0.0.1:8000/
Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order:
^hello/$
The current URL, , didn't match any of these.
My code in views.py looks like this:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world")
And urls.py:
from django.conf.urls import patterns, include, url
from mysite.views import hello
urlpatterns = patterns('',
url('^hello/$', hello)
)
When I only use "^$" for the first regex argument in the url() function it works. But whenever I try to match it with a regular expression, like the one above, which should match the HttpResponse in hello() it never works. I've tried countless of variations of hello without success. I might also add that I've tried it on both Linux and Windows. What can be a possible origin of this problem?
The reason for 404 is that there is no matching regex for http://127.0.0.1:8000/ page in your urlpatterns:
urlpatterns = patterns('',
url('^hello/$', hello)
)
^hello/$ regex matches only http://127.0.0.1:8000/hello/ url.
You're defining a URL for /hello but you aren't actually going to that URL, you're going to /. You need to actually use the "hello" in your browser's address bar.

How to define url which accept everykind of strings in django

In django, I defined url like that
(r'^checkstring/(?P<string>\w+)/$',views.check_str,name='check str')
But, When i enter string inputs like ibrahim.yilmaz, ibrahi!m or ibrahim#ibrahim.com, it returns http 404.
So how can i write the url which accept everykind of string?
any help will be appreciated.
İbrahim
Django uses regular expressions to match incoming requests. In python a dot (.) matches any character except a newline. See docs for more information and try:
(r'^checkstring/(?P<string>.+)/$',views.check_str,name='check str')
Also keep in mind that this will accept any character (including the forward slash) which may not be desirable for you. Be sure to test to make sure everything works as you would expect.
In Django >= 2.0, you can implement in the following way.
from django.urls import path
urlpatterns = [
...
path('polls/<string>/$','polls.views.detail')
...
]
For Django 2.0
import re_path in urls.py file
like this:from django.urls import re_path
then in the urlpatterns write the following code:
urlpatterns = [ re_path('prefixs/.*', your_ViewClass_name.as_view()), ]

Categories