Django Redirects - python

I'm trying to get people on my site to access an entirely separate part of the site based on what user group they belong too. Here is the logic I've written so far:
if request.user:
if request.user.groups.filter(name='A').count() >= 1:
return HttpResponseRedirect('/pageA')
elif request.user.groups.filter(name='B').count() >= 1:
return HttpResponseRedirect('/pageB')
else:
return HttpResponseRedirect('/login')
And then urls:
url(r'', 'main.views.getIndex'),
url(r'', include('a.urls')),
url(r'', include('b.urls')),
So basically, I have group A & group B - user can access "A" page and "B" page accordingly if they belong to the respective user group. Otherwise, they have to login (placeholder denial page).
The logic seems to make sense, but I keep getting "too many redirects" error. In fact, the page actually gets to the statement I want it too but then upon returning HttpResponseRedirect, it stops working.
Your help is much appreciated.

The following pattern will match all urls
url(r'', 'main.views.getIndex'),
So if the getIndex returns a redirect, you will get an infinite redirect loop.
If you only want the url pattern to match the index url (i.e. /), then change it to:
url(r'^$', 'main.views.getIndex'),
The caret ^ matches the beginning of the string and the dollar $ matches the end of the string. Therefore ^$ only matches the empty string ''. By contrast, the regex r'' matches all strings.

Well I don't know what code you have in a.urls and b.urls, but I will give you the way I almost always use when I should apply a redirect. It is only a new way you can have, of course. For example supposing you have this entry on a.urls:
from django.conf.urls.defaults import *
urlpatterns = patterns('appA.views',
url(r'^pageA/$', 'pageA_view', name='pageA'),
)
you can apply this:
from django.shortcuts import redirect
# In your code
if request.user.groups.filter(name='A').count() >= 1:
return redirect('pageA')
It is another way you can accomplish this task. You can follow your idea too, but for a better understanding it would be useful to see what you have on your a.urls and b.urls.
Well, I just see the answer after I posted me response. Anyway, maybe it can help to someone.

Related

How does Django map the urls when there is ambiguity

I have the url patterns in my project urls.py
url(r'^', include('app.urls')),
url(r'^api/app/', include('app.url.router_urls')),
and in the app.urls i have something like
url(r'^api/app/user$', views.user_validator),
and in the app.url.router_urls i have something like
url('^v1/', include('app.url.app_v1.urls'))
I have a question around these.
so when the request is BASE_URL/api/app/{user} which url will be mapped to this?
and how about BASE_URL/api/app/v1/ which url will be mapped.
this will map first with ^ right and will use the app.urls for both?
thanks
Django will fire the first view for which the URL matches. It thus evaluates the urls top-to-bottom.
It will thus first look to the included app.urls and if that matches (if you visited hostname/api/app/user, it will "fire" that view.
Note that here your user is not a variable, this is simply the word user, so if you visit {user}, it will keep looking, but since none of the patterns "fire", it will thus return a 404.
You can work with URL parameters, with:
url(r'^api/app/(?P<user>[\w{}]+)$', views.user_validator),
If we do this however, it will also match with hostname/api/app/v1, since then it sees that [\w{}]+ matches with v1.
Therefore it is important to order the url patterns from more specific to less specific, or even better: design the URL patterns such that there is no overlap.
Note: As of django-3.1, url(…) [Django-doc] is
deprecated in favor of re_path(…) [Django-doc].
Furthermore a new syntax for paths has been introduced with path converters: you
use path(…) [Django-doc] for that.

Possible to escape or otherwise pass a value that includes / in Django URL

I'm building a tool using Django that works with the part numbers that my company uses, one set of part numbers includes /'s which I didn't realize when I set up the url to access the part summary.
Now when try to pass one of those part numbers it breaks things, is there a way to work around this? I'd like to avoid changing the part number or adding a unique id with no other meaning to the model.
an example part number that causes the problem is P-030-P-401/ND the url pattern is /parts/
Thanks in advance
If you are allowed to change the route a bit, this is an option with just a few characters difference:
www.domain.com/parts/?part_id=P-030-P-401/ND
Example setup:
urls.py
urlpatterns = [
# other paths here
path("parts/", view_test),
]
views.py
def view_test(request):
part_id = request.GET.get("part_id")
return render(request, "parts/test.html", {"part_id": part_id})
test.html
{{part_id}}
Depending on browser settings maybe replace / with %2F, but it's working with the slash for me on Firefox.

Why won't my regex parse this URL in Django?

Currently working in Django, and I'm trying to set things up so that a form on one page calls a specific URL, for which the appropriate view is rendered. I'm having trouble with the regular expression that parses the URL, as it won't read the value '\?' as an escaped question mark, which is what I believe it should be doing. The following RE checks out on Pythex.
When the app submits the form, it calls the URL:
http://127.0.0.1:8000/map/?street=62+torrey+pines+cove&city=san+diego&state=CA&radius=50&drg=4
In my project level urls.py file, I have the following:
url(r'^map/', include('healthcare_search.urls', namespace="healthcare_search")),
This calls my app level urls.py file, where I have:
url(r'^\?street=(?P<street>[a-z0-9+]+)&city=(?P<city>[a-z+]+)&state=(?P<state>[a-z]{2})&radius=(?P<radius>[0-9]{1,3})&drg=(?P<drg>[0-9]{1,3})', views.map_hospitals, name = "map_hospitals"),
This just results in a 404 error, saying the URL doesn't match any of the patterns. I know that it's a RE problem, because I removed everything from the app level RE, and submitted just http://127.0.0.1:8000/map/ to see if it would call the right view, which it did successfully. Things seem to break apart on the '\?'. Any ideas what I'm doing wrong?
As a note, this is the first time I've written a regular expression, so my apologies if it is unclear or poorly written.
You don't want to get access to the variables that way. A better option is to get them from the request, since they'll be available in the request's dictionary of variables. In your view, you can get the value of street via request.GET.get('street', None), which will return the value if street is in the request or return None otherwise.

Django Url Not Resolving with Query Parameters

I have an issue where I need to pass in query parameters for a GET request, but Django is not resolving the URL correctly to the view.
My urls.py looks like this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^confirm_cancel',
'myapp.views.confirm_cancel_method',
name='myapp_confirm_cancel'),
)
When I goto /confirm_cancel?some_id=x I get a 404, telling me "No MyModel matches query." When I set a breakpoint in my view handler, it does not get hit when I goto that url.
However, if I goto /confirm_cancel/x/, my view breakpoint does get hit.
One more thing to note, this worked in Django 1.1, but is now broken since I upgraded to 1.2.
Any thoughts?
Thanks!
I don't think the problem is with your url. Are you using a shortcut like get_object_or_4o4 somewhere in your view? For example:
get_object_or_404(MyModel, pk=99)
would result in a "No MyModel matches given query, if there wasn't a record in your table with a primary key of 99.
We need to see what's in the corresponding view function.
Ideally, it should look something like this:
def confirm_cancel_method(request, some_id=None):
some_id = request.REQUEST.get('some_id', some_id)
some_record = get_object_or_404(SomeModel, pk=some_id)
...
update
Sorry, just saw your note about the breakpoint. One thing I'd recommend is changing the config to this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^confirm_cancel/?$',
'myapp.views.confirm_cancel_method',
name='myapp_confirm_cancel'),
)
Adding /?$ at the end means that only /confirm_cancel or /confirm_cancel/ will match the url. Right now because you don't have the ending $ anything starting with confirm_cancel will match. Fixing the pattern will at least resolve this issue.
I had copied out all the other url patterns in the urls.py in my post.
Turns out that the issue was that I had a r'^(?P<my_id>\w+)/?$' for one of the urls at the top of the urlpatterns.
Next time I'll learn to paste everything instead of cherry picking what I think are the offending lines of code.
Strange that this did not cause Django 1.1 to break... I guess it was a bug that was fixed in 1.2
Did you check if this was a case of the trailing slash?

Django: Arbitrary number of unnamed urls.py parameters

I have a Django model with a large number of fields and 20000+ table rows. To facilitate human readable URLs and the ability to break down the large list into arbitrary sublists, I would like to have a URL that looks like this:
/browse/<name1>/<value1>/<name2>/<value2>/ .... etc ....
where 'name' maps to a model attribute and 'value' is the search criteria for that attribute. Each "name" will be treated like a category to return subsets of the model instances where the categories match.
Now, this could be handled with GET parameters, but I prefer more readable URLs for both the user's sake and the search engines. These URLs subsets will be embedded on each page that displays this model, so it seems worth the effort to make pretty URLs.
Ideally each name/value pair will be passed to the view function as a parameter named name1, name2, etc. However, I don't believe it's possible to defined named patterns via a regex's matched text. Am I wrong there?
So, it seems I need to do something like this:
urlpatterns = patterns('',
url(r'^browse/(?:([\w]+)/([\w]+)/)+$', 'app.views.view', name="model_browse"),
)
It seems this should match any sets of two name/value pairs. While it matches it successfully, it only passes the last name/value pair as parameters to the view function. My guess is that each match is overwriting the previous match. Under the guess that the containing (?:...)+ is causing it, I tried a simple repeating pattern instead:
urlpatterns = patterns('',
url(r'^browse/([\w]+/)+$', 'app.views.view', name="model_browse"),
)
... and got the same problem, but this time *args only includes the last matched pattern.
Is this a limitation of Django's url dispatcher, and/or Python's regex support? It seems either of these methods should work. Is there a way to achieve this without hardcoding each possible model attribute in the URL as an optional (.*) pattern?
A possibility that you might consider is matching the entire string of possible values within the url pattern portion and pull out the specific pieces within your view. As an example:
urlpatterns = patterns('',
url(r'^browse/(?P<match>.+)/$', 'app.views.view', name='model_browse'),
)
def view(request, match):
pieces = match.split('/')
# even indexed pieces are the names, odd are values
...
No promises about the regexp I used, but I think you understand what I mean.
(Edited to try and fix the regexp.)
I agree with Adam, but I think the pattern in urls.py should be:
... r'^browse/(?P<match>.+)/$' ...
The '\w' will only match 'word' characters, but the '.' will match anything.
I've an alternative solution, which isn't quite different from the previous but it's more refined:
url(r'^my_app/(((list\/)((\w{1,})\/(\w{1,})\/(\w{1,3})\/){1,10})+)$'
I've used unnamed url parameters and a repetitive regexp. Not to get the "is not a valid regular expression: multiple repeat" i place a word at the beginning of the list.
I'm still working at the view receiving the list. But i think ill' go through the args or kwargs.. Cannot still say it exactly.
My 2 cents
Same answer came to me while reading the question.
I believe model_browse view is the best way to sort the query parameters and use it as a generic router.
I think the answer of Adam is more generic than my solution, but if you like to use a fixed number of arguments in the url, you could also do something like this:
The following example shows how to get all sales of a day for a location by entering the name of the store and the year, month and day.
urls.py:
urlpatterns = patterns('',
url(r'^baseurl/location/(?P<store>.+)/sales/(?P<year>[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9])-(?P<day>[0-9][0-9])/$', views.DailySalesAtLocationListAPIView.as_view(), name='daily-sales-at-location'),
)
Alternativly, you could also use the id of the store by changing (?P<store>.+) to (?P<store>[0-9]+). Note that location and sales are no keywords, they just improve readability of the url.
views.py
class DailySalesAtLocationListAPIView(generics.ListAPIView):
def get(self, request, store, year, month, day):
# here you can start using the values from the url
print store
print year
print month
print date
# now start filtering your model
Hope it helps anybody!
Best regards,
Michael

Categories

Resources