Right way to handle HttpResponseRedirect - django

I have a Django app I'm trying to deploy. The Apache setting is configured in the way that i access my wsgi app by the following URL:
sitename.com/~amartino
Meaning I have only a wsgi.py file in my public_html directory.
I access my Django site via URL:
sitename.com/~amartino/expofit
For that's the way its been set in urls.py.
urlpatterns = patterns('',
('/param_select/$',session_check(param_select)),
('registration/$',registration),
('result_show/(\d+)',session_check(result_show)),
('^expofit/$',media_clean(start)),
('result_pick/$',session_check(result_pick)),
('mail_report/$',session_check(mail_report)),
('notification/$',session_check(notification)),
However, the problem I'm getting (which didn't show up in development :) ) is that I'm using a hardcoded HttpResponseRedirect in views.py.
...
#If all fields are valid
return HttpResponseRedirect('/expofit/param_select/')
#else reload page
...
Since the production environment doesn't place my site in the root of the URL, i'm having errors now because the upper HttpResponseRedirect translates to
sitename.com/expofit/param_select/
which isn't recognized by Apache.
I suppose I could remove the slash and have:
return HttpResponseRedirect('expofit/param_select/')
which would result in:
sitename.com/~amartino/expofit/registration/expofit/param_select/
but that doesn't seem the right way to do it for I would end up with a huge URL in no time.
Where is the design/configuration flaw here?

"the problem I'm getting that I'm using a hardcoded HttpResponseRedirect"
Well, don't do that then. That's why Django provides the reverse function, which takes your url name and calculates the proper absolute URL.

Related

Persian text in url Django

I have some links that include Persian texts, such as:
http://sample.com/fields/طب%20نظامی
And in the view function I want to access to Persian part, so:
url = request.path_info
key = re.findall('/fields/(.+)', url)[0]
But I get the following error:
IndexError at /fields/
list index out of range
Actually, the problem is with the index zero because it can not see anything there! It should be noted that it is a Django project on IIS Server and I have successfully tested it with other servers and the local server. I think it has some thing related to IIS. Moreover I have tried to slugify the url without success. I can encode urls successfully, but I think it is not the actual answer to this question.
Based on the comments:
I checked the request.path too and the same problem. It contains:
/fields/
I implemented a sample django project in local server and here is my views:
def test(request):
t = request.path
return HttpResponse(t)
The results:
http://127.0.0.1:8000/تست/
/تست/
Without any problem.
Based on the #sytech comment, I have created a middlware.py in my app directory:
from django.core.handlers.wsgi import WSGIHandler
class SimpleMiddleware(WSGIHandler):
def __call__(self, environ, start_response):
print(environ['UNENCODED_URL'])
return super().__call__(environ, start_response)
and in settings.py:
MIDDLEWARE = [
...
'apps.middleware.SimpleMiddleware',
]
But I am getting the following error:
__call__() missing 1 required positional argument: 'start_response'
Assuming you don't have another problem in your rewrite configuration, on IIS, depending on your rewrite configuration, you may need to access this through the UNENCODED_URL variable which will contain the unencoded value.
This can be demonstrated in a simple WSGI middleware:
from django.core.handlers.wsgi import WSGIHandler
class MyHandler(WSGIHandler):
def __call__(self, environ, start_response):
print(environ['UNENCODED_URL'])
return super().__call__(environ, start_response)
You would see the unencoded URL and the path part that's in Persian would be passed %D8%B7%D8%A8%2520%D9%86%D8%B8%D8%A7%D9%85%DB%8C. Which you can then decode with urllib.parse.unquote
urllib.parse.unquote('%D8%B7%D8%A8%2520%D9%86%D8%B8%D8%A7%D9%85%DB%8C')
# طب%20نظامی
If you wanted, you could use a middleware to set this as an attribute on the request object or even override the request.path_info.
You must be using URL rewrite v7.1.1980 or higher for this to work.
You could also use the UNENCODED_URL directly in the rewrite rule, but that may result in headaches with routing.
I can encode urls successfully, but I think it is not the actual answer to this question.
Yeah, that is another option, but may result in other issues like this: IIS10 URL Rewrite 2.1 double encoding issue
You can do this by using python split() method
url = "http://sample.com/fields/طب%20نظامی"
url_key = url.split(sep="/", maxsplit=4)
url_key[-1]
output : 'طب%20نظامی'
in this url is splited by / which occurs 4 time in string so it will return a list like this
['http:', '', 'sample.com', 'fields', 'طب%20نظامی']
then extract result like this url_key[-1] from url_key
you can Split the URL by :
string = http://sample.com/fields/طب%20نظامی
last_part = string. Split("/")[-1]
print(last_part)
output :< طب%20نظامی >
slugify(last_part)
or
slugify(last_part, allow_unicode=True)
I guess This Will Help You :)

What would be considered the root directory to a third party javascript in Django

When using Send Pulse they instruct you place a javascript in the head of your template. This javascript then refers to 2 other scripts that they instruct you to place in the root of you web site. Where can these be placed so that their javascript will automatically find them in the "web root"?
The point is that the service is expecting to find the scripts directly under /, eg mywebsite.com/script1.js. But in Django static files are usually under /static or the equivalent. There is nowhere you can just "place" them to get them to appear at the right URL.
But that doesn't mean you can't do it. The best thing to do would be to add an explicit mapping in your web server (nginx or Apache) for those scripts. For example, in nginx:
location /script1.js { alias /path/to/staticdir/script1.js; }
You have a number of possible options. In no particular order:
#daniel-roseman's suggestion of using a rewrite/alias configured in your webserver
Modify the javascript that you're going to place in the head of your page, so that it loads the scripts from your /static folder (followed by placing those scripts there, of course)
Use an HttpResponse to return these script(s) from a view function, and then map the target URLs (like mywebsite.com/script1.js) to the view.
This might look like:
# urls.py - assuming >= Django 2.0
from django.urls import path
urlpatterns = [
# place script1.js into your static folder, then reference its location within the static folder
path('script1.js', views.javascript_loader, {'script_path': 'script1.js'}),
]
# views.py
from django.http import HttpResponse
from django.conf import settings
import os
def javascript_loader(request, script_path):
# note: you should cache this content for the use case you've described, just
# consider this an illustration of how to load/return content from a static
# file using a view.
full_script_path = os.path.join(settings.STATIC_ROOT, script_path)
with open(full_script_path, 'r') as f:
javascript_contents = f.read()
return HttpResponse(javascript_contents, mimetype="text/javascript")
Again, not sure which solution would be best for your needs, but one of those should get you the result you need.

Django URL reversing NoReverseMatch issue

I'm trying to use reverse to redirect a user to a login page from a third party App I'm using.
The URL config has:
urlpatterns = [
# authentication / association
url(r'^login/(?P<backend>[^/]+){0}$'.format(extra), views.auth,
name='begin'),
How can I accomplish this? I've tried
return redirect(reverse('social:login'), args=('facebook',))
and
return redirect(reverse('social:login'), kwargs={'backend':fb})
(to get to /login/facebook) but I'm getting a NoReverseMatch
The Django URL system and RegExes are confusing me a bit =(
EDIT: All right, it looks like I was making a mess with these URLs.
A simple solution that works (thank you #Alasdair in the comments):
return redirect('social:begin', backend='facebook')

django unicode url

on deployment (Django + Dreamhost + passenger_wsgi)
in my urls.py:
url(ur'^(?P<url>.+)/$', 'alp.news.views.blog_dispatcher', name='blog_dispatcher'),
the link:
domain.name/%D0%98%D0%BD%D1%84%D0%B02/
leads to (looks like redirection):
domain.name/%25d0%2598%25d0%25bd%25d1%2584%25d0%25b02/
so, the "url" variable in my view = "%25d0%2598%25d0%25bd%25d1%2584%25d0%25b02"
locally (or using dev server)
When I use runserver command, even on deployment, it works well.
Ofcourse I could use urllib and unquote the url in my view, but the string in url still transforming '%' -> '%25'.
Have no idea, where does the magic begin: in passenger or wsgi app
May be someone could clear up ...
the magic was in dreamhost's 301 redirection, which double-quoted the path

Decoupling django apps 2 - how to get object information from a slug in the URL

I am trying to de-couple two apps:
Locations - app containing details about some location (town, country, place etc)
Directory - app containing details of places of interest (shop, railway station, pub, etc) - all categorised.
Both locations.Location and directory.Item contain lat/lng coords and I can find items within a certain distance of a specific lat/lng coord.
I'd like to use the following URL structure:
/locations/<location_slug>/directory/<category_slug>/
But I don't want to make my directory app reliant on my location app.
How can I translate this url to use a view like this in my directory app?
items_near(lat, lng, distance, category):
A work around would be to create a new view somewhere that translates this - but where should I put that? if it goes in the Directory app, then I've coupled that with my Location app, and vice versa.
Would a good idea be to place this workaround code inside my project URLs file? Thus keeping clear of both apps? Any issues with doing it like this?
For your urlpattern to work, the view function invoked has to be aware of both Locations and Directories. The short answer is you can put this view function anywhere you want - it's just a python function. But there might be a few logical places for it, outside of your Directory or Location app, that make sense.
First off, I would not put that view code in in your top-level urls.py, as that file is intended for URLconf related code.
A few options of where to put your view:
Create a new view function in a file that lives outside of any particular app. <project_root>/views.py is one possibility. There is nothing wrong with this view calling the item_near(..) view from the Directory app.
# in myproject/urls.py
urlpatterns = (
...
(r'/locations/(?P<location_slug>[\w\-]+)/directory/(?P<category_slug>[\w\-]+)/',
'myproject.views.items_near_from_slug')
)
# in myproject/views.py
from directory.views import items_near
def items_near_from_slug(request, location_slug, category_slug):
location = get_object_or_404(Location, slug=location_slug)
distance = 2 # not sure where this comes from
# And then just invoke the view from your Directory app
return items_near(request, location.lat, location.lng, distance, category_slug)
Create a new app and put the code there, in <my_new_app>/views.py. There is no requirement that a Django app need to have a models.py, urls.py, etc. Just make sure to include the __init__.py if you want Django to load the app properly (if, for instance, you want Django to automatically find templatetags or app specific templates).
Personally, I would go with option 1 only if the project is relatively simple, and <project_root>/views.py is not in danger of becoming cluttered with views for everything. I would go with option 2 otherwise, especially if you anticipate having other code that needs to be aware of both Locations and Directories. With option 2, you can collect the relevant urlpatterns in their own app-specific urls.py as well.
From the django docs here if you're using django >=1.1 then you can pass any captured info into the included application. So splitting across a few files:
# in locations.urls.py
urlpatterns = ('',
(r'location/(?P<location_slug>.*?)/', include('directory.urls')),
#other stuff
)
# in directory.urls.py
urlpatterns = ('',
(r'directory/(?P<directory_slug>.*?)/', 'directory.views.someview'),
#other stuff
)
# in directory.views.py
def someview(request, location_slug = None, directory_slug = None):
#do stuff
Hope that helps. If you're in django < 1.1 I have no idea.
Irrespective of how much ever "re-usable" you make your app, inevitably there is a need for site-specific code.
I think it is logical to create a "site-specific" application that uses the views of the reusable and decoupled apps.