On a legacy app, I need to check if a URL exists, and if it does not, to redirect it to another location. The problem is that I need to check if that url is present in a set of values, in the urls file and I'm not clear on how best to do that.
For example, both projects and cities are sharing the same url pattern. e.g. /projects/london and /projects/my-project-name.
I want to first check if the slug matches a city, and if it does not to then return the project view (cities cannot match project names).
My urls are currently structured as follows:
url(r'^projects/(?P<project-name>[-\w]+)', get_project, name='project-view'),
url(r'^projects/.*', get_city, name='city-view'),
I know this is very messy, and a bad overall pattern but unfortunately it's not something that can be changed at the moment. So my goal is to figure out if I can first check if the project-name could be a city, and if it is, to redirect onto that view without falling into a redirect loop.
I wondered if I could do something like this:
url(r'^projects/(?P<city>london|paris|new-york)/', get_city, name='city-view'),
where london|paris|new-york are generated dynamically
You can dynamically generate a url with all of the city names, but the url will be cached once django accesses it the first time, so in order to modify the url regex, you'd have to restart the django process. If that's fine for your purposes, you can generate the url like this:
url(r'^projects/(?P<city>{})/$'.format(city_slugs.join('|')),
get_city, name='city-view')
But, it would probably be better to create a view routing method that implements the logic to send requests to their appropriate view:
# urls.py
# ...
url(r'^projects/(?P<slug>[-\w]+)/$',
project_city_router, name='project-city-router'),
# ...
# views.py
def is_a_city(slug):
# If they're in the database, something like:
# return City.objects.filter(slug=slug).exists()
return slug in ['london', 'paris', 'new-york', '...']
def project_city_router(request, slug=None):
if not slug:
# /projects/
return render(request, 'my/template.html', {'foo': 'bar'})
elif is_a_city(slug):
# /projects/<city>/
return get_city(request, city=slug)
else:
# /projects/<project-name/
return get_project(request, project_name=slug)
With this router, if the slug argument is a project or city, it returns the result of the get_project or get_city view itself.
This also allows for your list of cities to be checked dynamically against a database, or file.
Related
Is it possible to pass context through the reverse function in Django in some way like reverse('foo', context={'bar':'baz'})? Or is there a better workaround?
As already described by Sir WillemVanOnsem in the above comment.
You can't provide context in reverse as it only produces a string: a path, eventually it goes to view.
reverse() can only take args and kwargs, see Reversing namespaced URLs for more detail.
Reverse generates an URL. The URL can parse or supply extra context. In urls.py,
path( 'action/<str:context>/', MyView.as_view(), name='foo' )
then
reverse('app:foo', kwargs={'context':'bar:baz+quux:help'} )
will generate the URL ending
.../appname/action/bar:baz+quux:help
and your view will parse context:
context = self.kwargs.get( context, '')
context_dir = {}
for kv in context.split('+'):
keyval = kv.split(':')
context_dir[ keyval[0].strip() ] = keyval[1].strip()
or something like this, ending with context_dir as {'bar':'baz', 'quux':'help'}
Alternatively you can append a querystring to the URL returned by reverse and retrieve that in the view you redirect to via request.GET
url = reverse('foo') + '?bar=baz&quux=help'
redirect, and then in that view request.GET.get('bar') will return "baz" etc.
Finally you can stuff an almost arbitrarily complex context into the user's session (which gets stored either as a cookie in his browser, or an object in your database). This is the most general but also the most complex. See the doc for using Django sessions
I am trying to make a query system for my website, i think the best way and the most compact would be to assign search variable using url pattern.
So for example, i want to search objects of model User:
User sends HttpRequest to following url:
https://127.0.0.1/search/q="admin"
Now HttpRequest is also sent to search view, we somehow get q variable data.
def search(request):
for query in User.objects.all():
if q in query: # < We somehow need to get data of 'q'.
return HttpResponse(q)
Since i have admin in User.objects.all(), this should return HttpResponse of 'admin'.
How can this url pattern be made? So i can assign q variable from the url and then send it to system to find it?
I have problems with this URL:
https://127.0.0.1/search/q="admin"
There is no ? in the URL, so there is no query string, it's all part of the "path". Using characters like = and " in there will confuse a lot of things, if it works at all.
Either just do
https://127.0.0.1/search/admin
With an URL pattern like r'^search/(?P<querystring>.+)$', or
https://127.0.0.1/search/?q=admin
In this case the query string will be in request.GET['q']; it's also possible to use Django forms to process query parameters (e.g. for validating them).
You can capture named strings from URLs like this:
urls.py:
urlpatterns = [
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
views.py:
def page(request, num="1"):
I am creating this functionality with a Django application I have. I want to log all pages the user visits and display it to him.
I am using a middleware to achieve it.
class LoggingMiddleware:
"""
Class used to register and fetch pages where the user has been visiting.
"""
def process_template_response(self, request, response):
if request.user.is_authenticated():
UserHistory.objects.create(user=request.user, page_name=request.path, url=request.path)
if response.context_data:
response.context_data['user_history'] = UserHistory.objects.filter(user=request.user)
return response
I want to name these UserHistory entries in the database, instead of just set the url as the name (as it i s now).
I have though of adding a variable to all views I have, in a way that the request object has something like request.page_name.
Can someone think of a better way to do it?
I am working through the Pyramid authorization tutorial and I have noticed the pattern where
logged_in = request.authenticated_userid
is added to each view dictionary. Can it be avoided? I.e. is there a configuration which automatically ads user id to each view. Or is there a way to create a base, abstract view with the user id and inherit from it?
Part of the code from the tutorial:
#view_config(context='.models.Page', renderer='templates/view.pt', permission='view')
def view_page(context, request):
# not relevant code
return dict(page = context, content = content, edit_url = edit_url,
logged_in = request.authenticated_userid)
#view_config(name='add_page', context='.models.Wiki', renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
# not relevant code
return dict(page=page, save_url=save_url,
logged_in=request.authenticated_userid)
It's been awhile since I last looked, but I think logged_in in the samples is just an example to use to conditionally check if there is a logged on user or not. You could probably just as easily refer to request.authenticated_userid within any of your views or templates, too, and get the same behavior and not have to explicitly add a status to the response dict. The request object should be available to be referenced in your view templates, too.
Alternatively, I've used their cookbook to add a user object to the request to make a friendly request.user object that I can use to both check for logged in status where needed, plus get at my other user object details if I need to as well.
I have a model named Agency.agency has a field named URL,for example I add 2 Agencies that the first one give the value of A to URL and the second one give the value of B to URL field.now I wanna override save_model method in index in views.py to add Agencie's URL to urls.py when adding an Agency,like this:
(r'^airAgency/A/$','airAgency.views.index'),
(r'^airAgency/B/$','airAgency.views.index'),
so,when enter http://127.0.0.1:8080/airAgency/A the index view detect which Agency I wanna access and pass its data to the page.now I have 2 question:
how can I add/remove url to urls.py when overriding save method in views.py
when user enter a URL in browser how can I parse it and find out which Agency he wanna access to send that Agency Information.
about the first question I searched a lot but I didn't find anything.for second question I googled and I found out how to parse the requested URL,but U think doing string search in Agency Table based on its URL field is a good way?
As others have said and/or pointed to, don't hardcode specific Agencies into your urls.py
Keep it generic and DRY by allowing variables in your urls
# urls
(r'^airAgency/(?P<name>[a-zA-Z0-9]+)/$', 'airAgency.views.index'),
# this passes the value there as 'name' to the view for index
#views
def index(request, name): # it needs to know name will be passed to it
some_query = Agency.objects.filter( agency_name = name )
#should also add catching for unknown objects to go to 404s
...
return some_sort_of_http_response
more examples are in the docs