Get View associated with a URL [duplicate] - django

Given a uri like /home/ I want to find the view function that this corresponds to, preferably in a form like app.views.home or just <app_label>.<view_func>. Is there a function that will give me this?

You can use the resolve method provided by django to get the function. You can use the __module__ attribute of the function returned to get the app label. This will return a string like project.app.views. So something like this:
from django.urls import resolve
myfunc, myargs, mykwargs = resolve("/hello_world/")
mymodule = myfunc.__module__
In case one needs the class of the view since a class based view is being used one can access the view_class of the returned function:
view_class = myfunc.view_class

From Django 2.0 onward django.core.urlresolvers module has been moved to django.urls.
You will need to do this:
from django.urls import resolve
myfunc, myargs, mykwargs = resolve("/hello_world/")
mymodule = myfunc.__module__

Since Django 1.3 (March 2011) the resolve function in the urlresolvers module returns a ResolverMatch object. Which provides access to all attributes of the resolved URL match, including the view callable path.
>>> from django.core.urlresolvers import resolve
>>> match = resolve('/')
>>> match.func
<function apps.core.views.HomeView>
>>> match._func_path
'apps.core.views.HomeView'

1. Generate a text file with all URLs with corresponding view functions
./manage.py show_urls --format pretty-json --settings=<path-to-settings> > urls.txt
example
./manage.py show_urls --format pretty-json --settings=settings2.testing > urls.txt
2. Look for your URL in the output file urls.txt
{
"url": "/v3/affiliate/commission/",
"module": "api.views.affiliate.CommissionView",
"name": "affiliate-commission",
},

All the others focus on just the module or string representation of the view. However, if you want to directly access the view object for some reason, this could be handy
resolve('the_path/').func.cls
This gives the view object itself, this works on class based view, I haven't tested it on a function based view though.

Based on KillianDS's answer, here's my solution:
from django.core.urlresolvers import resolve
def response(request, template=None, vars={}):
if template is None:
view_func = resolve(request.META['REQUEST_URI'])[0]
app_label = view_func.__module__.rsplit('.', 1)[1]
view_name = view_func.__name__
template = '%s.html' % os.path.join(app_label, view_name)
return render_to_response(template, vars, context_instance=RequestContext(request))
Now you can just call return response(request) at the end of your view funcs and it will automatically load up app/view.html as the template and pass in the request context.

Related

how to have options in urls in django 2.0

In Django 1 I used to have url choices like this:
url('meeting/(?P<action>edit|delete)/', views.meeting_view, name='meeting'),
How I do this in Django 2.0 with the <> syntax:
Maybe something like this?
path('meeting/(<action:edit|delete>)/', views.meeting_view, name='meeting'),
If I understand the documentation, your first syntax should work right out-of-the-box.
Anyway here's how you could do with the new syntax:
First file = make a Python package converters and add edit_or_delete.py with that:
import re
class EditOrDeleteConverter:
regex = '(edit|delete)'
def to_python(self, value):
result = re.match(regex, value)
return result.group() if result is not None else ''
def to_url(self, value):
result = re.match(regex, value)
return result.group() if result is not None else ''
And for your urls.py file, this:
from django.urls import register_converter, path
from . import converters, views
register_converter(converters.EditOrDeleteConverter, 'edit_or_delete')
urlpatterns = [
path('meeting/<edit_or_delete:action>/', views.meeting_view, name='meeting'),
]
I would not use verbs in urls to indicate the purpose. Rather, rely on HTTP verbs such as GET, PUT, POST, DELETE and handle them in your view. That way, you can have just one view class handling all those different methods with just one URL.

how to get a list of all views in a django application?

Is there any way to get a list of all views in an django app? I have googled for answer. All answers shows a way to get list of urls.
Getting list of all the views of a Django project:
To get all the views present in a Django project, we create a function get_all_view_names() which takes urlpatterns as input and returns the complete list of views being used in the project as the output.
First, we import the root_urlconf module using settings.ROOT_URLCONF. Then root_urlconf.urls.urlpatterns will give us the list of project's urlpatterns.
The above urlpatterns list contains RegexURLPattern and RegexURLResolver objects. Accessing .urlpatterns on a RegexURLResolver will further give us a list of RegexURLPattern and RegexURLResolver objects.
A RegexURLPattern object will give us the view name which we are interested in. The callback attribute on it contains the callable view. When we pass either a string in our urls like 'foo_app.views.view_name' representing the path to a module and a view function name, or a callable view, then callback attribute is set to this. Further accessing .func_name will give us the view name.
We call the function get_all_view_names() recursively and add the view names obtained from a RegexURLPattern object to a global list VIEW_NAMES.
from django.conf import settings
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern
root_urlconf = __import__(settings.ROOT_URLCONF) # import root_urlconf module
all_urlpatterns = root_urlconf.urls.urlpatterns # project's urlpatterns
VIEW_NAMES = [] # maintain a global list
def get_all_view_names(urlpatterns):
global VIEW_NAMES
for pattern in urlpatterns:
if isinstance(pattern, RegexURLResolver):
get_all_view_names(pattern.url_patterns) # call this function recursively
elif isinstance(pattern, RegexURLPattern):
view_name = pattern.callback.func_name # get the view name
VIEW_NAMES.append(view_name) # add the view to the global list
return VIEW_NAMES
get_all_view_names(all_urlpatterns)
Getting list of all the views in a Django application:
To get the list of all the views present in a Django application, we will use the get_all_view_names() function defined above.
We will first import all the urlpatterns of the application and pass this list to the get_all_view_names() function.
from my_app.urls import urlpatterns as my_app_urlpatterns # import urlpatterns of the app
my_app_views = get_all_view_names(my_app_urlpatterns) # call the function with app's urlpatterns as the argument
my_app_views gives us the list of all the views present in my_app Django app.
Adding on to above fix by Rahul, if anyone is using Python3, you will need to use __name__ instead of func_name:
...
view_name = pattern.callback.__name__
...
otherwise you will get the following:
AttributeError: 'function' object has no attribute 'get_all_view_names'
(Thanks to scipy-gitbot at https://github.com/scipy/scipy/issues/2101#issuecomment-17027406
As an alternative, if you are disinclined to using global variables, here is what I ended up using :
all_urlpatterns = __import__(settings.ROOT_URLCONF).urls.urlpatterns
detail_views_list = []
def get_all_view_names(urlpatterns):
for pattern in urlpatterns:
if isinstance(pattern, RegexURLResolver):
get_all_view_names(pattern.url_patterns)
elif isinstance(pattern, RegexURLPattern):
detail_views_list.append(pattern.callback.__name__)
get_all_view_names(all_urlpatterns)
all_views_list = []
# remove redundant entries and specific ones we don't care about
for each in detail_views_list:
if each not in "serve add_view change_view changelist_view history_view delete_view RedirectView":
if each not in all_views_list:
all_views_list.append(each)
Then you can just iterate through all_views_list to get the list of filtered views.
update: Mar 1 2018
In Django 2.0, django.core.urlresolvers is moved to django.urls. RegexURLPattern and RegexURLResolver are renamed to URLPattern and URLResolver. So you should use
from django.urls import URLResolver, URLPattern
instead of
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern
if you are using Django 2.
Get all Django and DRF views w/o using global vars
def get_all_views(urlpatterns, views=None):
views = views or {}
for pattern in urlpatterns:
if hasattr(pattern, 'url_patterns'):
get_all_views(pattern.url_patterns, views=views)
else:
if hasattr(pattern.callback, 'cls'):
view = pattern.callback.cls
elif hasattr(pattern.callback, 'view_class'):
view = pattern.callback.view_class
else:
view = pattern.callback
views[pattern.name] = view
return views

Accessing URL parameter from context_processor

Let's say we have the following URL:
urlpatterns = patterns('',
...
url(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
)
I want to create my own context_processing which will process actions based on the parameter. My issue here, is that I really don't know how to access the parameter...
It is easy to access other GET parameter but for the one embedded in the URL i'm quite stuck.
def year_processor(request):
# How do i access year from the request object???
do_some_stuff(year)
return result
You may try django.core.urlresolvers.resolve where you can find more information (eg. url_name) about url that being processed:
from django.core.urlresolvers import resolve
def year_processor(request):
func, args, kwargs = resolve(request.path)
if 'year' in kwargs:
do_some_stuff(kwargs['year'])
...
Look at request.resolver_match, this should have what you need:
request.resolver_match.kwargs["year"]

Properly storing values passed in URL in Django

I have the following URL:
http://localhost:8000/store/add/?points=5
I want to extract the number of points from my URL.
In my views.py, I have:
points = request.GET.get('points',0)
The problem is that it never finds points, so it uses the default of 0.
Any insight into what I'm doing wrong?
My urls.py
from django.conf.urls.defaults import *
from store.models import Part, Category, UniPart, LibraryRequest
from django.views.generic.list_detail import object_list
from voting.views import vote_on_object
urlpatterns=patterns('',
#/store/
url(r'^$','store.views.all_models',name="all_models"),
#/integer/view_part
url(r'^(\d+)/view_part/$','store.views.view_part',name="view_part"),
url(r'^your_models/$','store.views.your_models',name="your_models"),#/your_model
url(r'^user_models/(?P<username>\w+)/$','store.views.user_models',name="user_models"),
url(r'^add/(?P<points>\d+)/','store.views.add_model'),
Snipped from views.py:
def add_model(request, points=None):
print points
Well, your urls.py says that you should use following url /store/add/5, and in your views.py you need to have view
def add_model(request, points=None):
print points
If you want points as a GET parameter change your urls.py as following:
url(r'^add$','store.views.add_model', name='add_model'),
And then you can pass points as /store/add?points=5 and extract it from the URL as
points = request.GET.get('points')
UPDATE
Also in a future to avoid such problems I suggest you to add name parameter to your routes in urls.py (see above) and use reverse in your views (ex. reverse('add_model', kwargs={'points': 5}) and url in your templates (ex. {% url 'add_model' 5 %})
In that case all urls in your application will be generated automatically based on routes in your urls.py files.
Use the following code:
points = request.GET.get('points')
If you are passing more than one variable it can be done in two ways:
METHOD 1:
In your urls.py.
(r'^store/add1/?integer=(?P<category>\d+)/?string=(?P<keyword>\w+)$', 'view_function_name'),
You can get the above values in your views using the following:
def function_name(request):
int_value = request.GET.get('integer')
str_value = reuest.GET.get('string')
And you can also use the pattern given below:
METHOD 2:
In your urls.py.
urlpatterns = patterns('model_name.views',
(r'^store/add1/(?P<integer>\d+)/(?P<string>\w+)/', 'function_name')
)
In your views.py:
def function_name(request, integer= None, string = None):
print integer
print string
#Do whatever you wish with this value
The second method will be more easy for you.

How do I construct a Django reverse/url using query args?

I have URLs like http://example.com/depict?smiles=CO&width=200&height=200 (and with several other optional arguments)
My urls.py contains:
urlpatterns = patterns('',
(r'^$', 'cansmi.index'),
(r'^cansmi$', 'cansmi.cansmi'),
url(r'^depict$', cyclops.django.depict, name="cyclops-depict"),
I can go to that URL and get the 200x200 PNG that was constructed, so I know that part works.
In my template from the "cansmi.cansmi" response I want to construct a URL for the named template "cyclops-depict" given some query parameters. I thought I could do
{% url cyclops-depict smiles=input_smiles width=200 height=200 %}
where "input_smiles" is an input to the template via a form submission. In this case it's the string "CO" and I thought it would create a URL like the one at top.
This template fails with a TemplateSyntaxError:
Caught an exception while rendering: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': u'CO', 'height': 200, 'width': 200}' not found.
This is a rather common error message both here on StackOverflow and elsewhere. In every case I found, people were using them with parameters in the URL path regexp, which is not the case I have where the parameters go into the query.
That means I'm doing it wrong. How do I do it right? That is, I want to construct the full URL, including path and query parameters, using something in the template.
For reference,
% python manage.py shell
Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.core.urlresolvers import reverse
>>> reverse("cyclops-depict", kwargs=dict())
'/depict'
>>> reverse("cyclops-depict", kwargs=dict(smiles="CO"))
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 356, in reverse
*args, **kwargs)))
File "/Library/Python/2.6/site-packages/django/core/urlresolvers.py", line 302, in reverse
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
NoReverseMatch: Reverse for 'cyclops-depict' with arguments '()' and keyword arguments '{'smiles': 'CO'}' not found.
Building an url with query string by string concatenation as suggested by some answers is as bad idea as building SQL queries by string concatenation. It is complicated, unelegant and especially dangerous with a user provided (untrusted) input. Unfortunately Django does not offer an easy possibility to pass query parameters to the reverse function.
Python standard urllib however provides the desired query string encoding functionality.
In my application I've created a helper function:
def url_with_querystring(path, **kwargs):
return path + '?' + urllib.urlencode(kwargs) # for Python 3, use urllib.parse.urlencode instead
Then I call it in the view as follows:
quick_add_order_url = url_with_querystring(reverse(order_add),
responsible=employee.id, scheduled_for=datetime.date.today(),
subject='hello world!')
# http://localhost/myapp/order/add/?responsible=5&
# scheduled_for=2011-03-17&subject=hello+world%21
Please note the proper encoding of special characters like space and exclamation mark!
Your regular expresion has no place holders (that's why you are getting NoReverseMatch):
url(r'^depict$', cyclops.django.depict, name="cyclops-depict"),
You could do it like this:
{% url cyclops-depict %}?smiles=CO&width=200&height=200
URLconf search does not include GET or POST parameters
Or if you wish to use {% url %} tag you should restructure your url pattern to something like
r'^depict/(?P<width>\d+)/(?P<height>\d+)/(?P<smiles>\w+)$'
then you could do something like
{% url cyclops-depict 200 200 "CO" %}
Follow-up:
Simple example for custom tag:
from django.core.urlresolvers import reverse
from django import template
register = template.Library()
#register.tag(name="myurl")
def myurl(parser, token):
tokens = token.split_contents()
return MyUrlNode(tokens[1:])
class MyUrlNode(template.Node):
def __init__(self, tokens):
self.tokens = tokens
def render(self, context):
url = reverse('cyclops-depict')
qs = '&'.join([t for t in self.tokens])
return '?'.join((url,qs))
You could use this tag in your templates like so:
{% myurl width=200 height=200 name=SomeName %}
and hopefully it should output something like
/depict?width=200&height=200&name=SomeName
I recommend to use builtin django's QueryDict. It also handles lists properly. End automatically escapes some special characters (like =, ?, /, '#'):
from django.http import QueryDict
from django.core.urlresolvers import reverse
q = QueryDict('', mutable=True)
q['some_key'] = 'some_value'
q.setlist('some_list', [1,2,3])
'%s?%s' % (reverse('some_view_name'), q.urlencode())
# '/some_url/?some_list=1&some_list=2&some_list=3&some_key=some_value'
q.appendlist('some_list', 4)
q['value_with_special_chars'] = 'hello=w#rld?'
'%s?%s' % (reverse('some_view_name'), q.urlencode())
# '/some_url/?value_with_special_chars=hello%3Dw%23rld%3F&some_list=1&some_list=2&some_list=3&some_list=4&some_key=some_value'
To use this in templates you will need to create custom template tag
Working variation of previous answers and my experience with dealing this stuff.
from django.urls import reverse
from django.utils.http import urlencode
def build_url(*args, **kwargs):
params = kwargs.pop('params', {})
url = reverse(*args, **kwargs)
if params:
url += '?' + urlencode(params)
return url
How to use:
>>> build_url('products-detail', kwargs={'pk': 1}, params={'category_id': 2})
'/api/v1/shop/products/1/?category_id=2'
The answer that used urllib is indeed good, however while it was trying to avoid strings concatenation, it used it in path + '?' + urllib.urlencode(kwargs). I believe this may create issues when the path has already some query parmas.
A modified function would look like:
def url_with_querystring(url, **kwargs):
url_parts = list(urlparse.urlparse(url))
query = dict(urlparse.parse_qsl(url_parts[4]))
query.update(kwargs)
url_parts[4] = urllib.urlencode(query)
return urlparse.urlunparse(url_parts)
Neither of the original answers addresses the related issue resolving URLs in view code. For future searchers, if you are trying to do this, use kwargs, something like:
reverse('myviewname', kwargs={'pk': value})