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

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.

Related

Use Escaped url in Django url regex mismatch

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

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 ...

(Django) Trying to figure out how I can get the right product using query parameters on Postman (url.py and views.py)

I have been building a sandwich shop app and I succeesfully build models.py and inserted all the product data. However, when I try to call specific products using Postman and the Django server, it keeps showing 404. What I typed on postman is like so:
http://10.58.1.157:8000/product/sandwich?product_id=1
Below are my codes for urls.py and views.py
So far, I have tried:
urls.py
from django.urls import path
from .views import ProductView
urlpatterns = [
path('sandwich/int:<product_id>/', ProductView.as_view()),
]
and:
urls.py
path('sandwich/(?P<product_id>[\w.-]+)/', ProductView.as_view())
views.py
import json
import bcrypt
import jwt
from django.views import View
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.db.models import Q
from .models import Product, Category, SubCategory
class ProductView(View):
def get(self, request):
product_id = request.GET.get('product_id', None)
return JsonResponse({'product_name':Product.objects.get(id=product_id).values()})
To clarify the GET request, I will add the screenshot of Postman below:
It seems like this is due to malformed URL path. That's whats typically indicative of 404-NotFound error.
You need to add question mark that essentially forms the querystring. It is processed and available as a dictionary-like object (a QueryDict) in request.GET in views.py
You can define it like so, with a ? using a REGEX pattern (You may also alter to your needs)
path('sandwich/(?P<product_id>[\w.-]+)/', ProductView.as_view()),
In your views.py you can filter them with
product_id = request.GET.get('product_id', None)
This should now hopefully return a response now that the URL cannot give a 404 error.
See this for an example
I finally solved the issue!
I looked at this page and improvised accordingly...
https://docs.djangoproject.com/en/3.0/topics/http/urls/#nested-arguments
the final version of request is:
http://127.0.0.1:8000/product/?product_id=1
and the urls.py is:
from django.urls import path, re_path
from .views import ProductView
urlpatterns = [
re_path(r'^(?:\?product_id=(?P<product_id>\d+)/)?$', ProductView.as_view()),
]

Django url dispatcher - wrong function

i am new to Django and i have some problem with Django URL dispatcher.
I have "prometfire" project and "homepage" app.
My goal is to connect this paths to their view functions:
127.0.0.1:8000 --> "homepage_view"
127.0.0.1:8000/welcome --> "welcome_view"
"homepage_view" works fine, but when i go to 127.0.0.1:8000/welcome i have same result as in "homepage_view", instead of "welcome_view" result.
Am i missing something?
Django 1.5
Python 2.7
#urls.py in prometfire
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', include('homepage.urls')),
url(r'^welcome/', include('homepage.urls')),
url(r'^admin/', include(admin.site.urls)),
)
#urls.py in homepage app
from django.conf.urls import patterns, include, url
urlpatterns = patterns('homepage.views',
url(r'^$', 'homepage_view'),
url(r'^welcome/', 'welcome_view'),
)
#views.py in homepage app
from django.shortcuts import render_to_response
from django.http import HttpResponse
def homepage_view(request):
return render_to_response('homepage.html',
{'name': 'bob'}
)
def welcome_view(request):
return HttpResponse('Welcome')
Your problem is that you are including your homepage urls twice. Remove the second entry
url(r'^welcome/', include('homepage.urls')),
This is explained in the docs on including other url confs
Whenever Django encounters include() (django.conf.urls.include()), it chops off whatever part of the URL matched up to that point and sends the remaining string to the included URLconf for further processing.
In your case, the 'welcome/' is removed from the url, which leaves '', which is matched by the url pattern for the homepage.
That's because it never enters the second condition for the app, it verifies the condition at the url root conf, welcome/, and after that goes directly to ^$ in the app. A solution would be remove the welcome/ from the url root.
The first welcome definition is redundant and is causing the "bug".

Python + Django page redirect

How do I accomplish a simple redirect (e.g. cflocation in ColdFusion, or header(location:http://) for PHP) in Django?
It's simple:
from django.http import HttpResponseRedirect
def myview(request):
...
return HttpResponseRedirect("/path/")
More info in the official Django docs
Update: Django 1.0
There is apparently a better way of doing this in Django now using generic views.
Example -
from django.views.generic.simple import redirect_to
urlpatterns = patterns('',
(r'^one/$', redirect_to, {'url': '/another/'}),
#etc...
)
There is more in the generic views documentation.
Credit - Carles Barrobés.
Update #2: Django 1.3+
In Django 1.5 redirect_to no longer exists and has been replaced by RedirectView. Credit to Yonatan
from django.views.generic import RedirectView
urlpatterns = patterns('',
(r'^one/$', RedirectView.as_view(url='/another/')),
)
Depending on what you want (i.e. if you do not want to do any additional pre-processing), it is simpler to just use Django's redirect_to generic view:
from django.views.generic.simple import redirect_to
urlpatterns = patterns('',
(r'^one/$', redirect_to, {'url': '/another/'}),
#etc...
)
See documentation for more advanced examples.
For Django 1.3+ use:
from django.views.generic import RedirectView
urlpatterns = patterns('',
(r'^one/$', RedirectView.as_view(url='/another/')),
)
There's actually a simpler way than having a view for each redirect - you can do it directly in urls.py:
from django.http import HttpResponsePermanentRedirect
urlpatterns = patterns(
'',
# ...normal patterns here...
(r'^bad-old-link\.php',
lambda request: HttpResponsePermanentRedirect('/nice-link')),
)
A target can be a callable as well as a string, which is what I'm using here.
Since Django 1.1, you can also use the simpler redirect shortcut:
from django.shortcuts import redirect
def myview(request):
return redirect('/path')
It also takes an optional permanent=True keyword argument.
If you want to redirect a whole subfolder, the url argument in RedirectView is actually interpolated, so you can do something like this in urls.py:
from django.conf.urls.defaults import url
from django.views.generic import RedirectView
urlpatterns = [
url(r'^old/(?P<path>.*)$', RedirectView.as_view(url='/new_path/%(path)s')),
]
The ?P<path> you capture will be fed into RedirectView. This captured variable will then be replaced in the url argument you gave, giving us /new_path/yay/mypath if your original path was /old/yay/mypath.
You can also do ….as_view(url='…', query_string=True) if you want to copy the query string over as well.
With Django version 1.3, the class based approach is:
from django.conf.urls.defaults import patterns, url
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^some-url/$', RedirectView.as_view(url='/redirect-url/'), name='some_redirect'),
)
This example lives in in urls.py
Beware. I did this on a development server and wanted to change it later.
Firefox 5 'caching' 301 redirects
I had to clear my caches to change it. In order to avoid this head-scratching in the future, I was able to make it temporary like so:
from django.views.generic import RedirectView
url(r'^source$', RedirectView.as_view(permanent=False,
url='/dest/')),
You can do this in the Admin section. It's explained in the documentation.
https://docs.djangoproject.com/en/dev/ref/contrib/redirects/
page_path = define in urls.py
def deletePolls(request):
pollId = deletePool(request.GET['id'])
return HttpResponseRedirect("/page_path/")
This should work in most versions of django, I am using it in 1.6.5:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
....
url(r'^(?P<location_id>\d+)/$', lambda x, location_id: HttpResponseRedirect(reverse('dailyreport_location', args=[location_id])), name='location_stats_redirect'),
....
)
You can still use the name of the url pattern instead of a hard coded url with this solution. The location_id parameter from the url is passed down to the lambda function.

Categories