Accessing URL parameter from context_processor - django

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"]

Related

Get View associated with a URL [duplicate]

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.

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.

Altering one query parameter in a url (Django)

I have a search page that takes a variety of parameters. I want to create a new URL by just altering one parameter in the query. Is there an easy way to do this - something like:
# example request url
http://example.com/search?q=foo&option=bar&option2=baz&change=before
# ideal template code
{% url_with change 'after' %}
# resulting url
http://example.com/search?q=foo&option=bar&option2=baz&change=after
So this would take the request url, alter one query parameter and then return the new url. Similar to what can be achieved in Perl's Catalyst using $c->uri_with({change => 'after'}).
Or is there a better way?
[UPDATED: removed references to pagination]
I did this simple tag which doesn't require any extra libraries:
#register.simple_tag
def url_replace(request, field, value):
dict_ = request.GET.copy()
dict_[field] = value
return dict_.urlencode()
Use as:
<a href="?{% url_replace request 'param' value %}">
It wil add 'param' to your url GET string if it's not there, or replace it with the new value if it's already there.
You also need the RequestContext request instance to be provided to your template from your view. More info here:
http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/
So, write a template tag around this:
from urlparse import urlparse, urlunparse
from django.http import QueryDict
def replace_query_param(url, attr, val):
(scheme, netloc, path, params, query, fragment) = urlparse(url)
query_dict = QueryDict(query).copy()
query_dict[attr] = val
query = query_dict.urlencode()
return urlunparse((scheme, netloc, path, params, query, fragment))
For a more comprehensive solution, use Zachary Voase's URLObject 2, which is very nicely done.
Note:
The urlparse module is renamed to urllib.parse in Python 3.
I improved mpaf's solution, to get request directly from tag.
#register.simple_tag(takes_context = True)
def url_replace(context, field, value):
dict_ = context['request'].GET.copy()
dict_[field] = value
return dict_.urlencode()
This worked pretty well for me. Allows you to set any number of parameters in the URL. Works nice for a pager, while keeping the rest of the query string.
from django import template
from urlobject import URLObject
register = template.Library()
#register.simple_tag(takes_context=True)
def url_set_param(context, **kwargs):
url = URLObject(context.request.get_full_path())
path = url.path
query = url.query
for k, v in kwargs.items():
query = query.set_param(k, v)
return '{}?{}'.format(path, query)
Then in the template:
<a href="{% url_set_param page=last %}">
There are a number of template tags for modifying the query string djangosnippets.org:
http://djangosnippets.org/snippets/553/
http://djangosnippets.org/snippets/826/
http://djangosnippets.org/snippets/1243/
I would say those are the most promising looking. One point in all of them is that you must be using django.core.context_processors.request in your TEMPLATE_CONTEXT_PROCESSORS.
You can try https://github.com/dcramer/django-paging
In addition to the snippets mentioned by Mark Lavin, Here's a list of other implementations I could find for a Django template tag which modifies the current HTTP GET query string.
On djangosnippets.org:
#2237 Manipulate URL query strings using context variables using a template tag by JHsaunders
#2332 Querystring Builder - create urls with GET params by jibberia
my favorite: #2413 Yet another query string template tag by atms
#2428 Add GET parameters from current request by naktinis
On PyPI:
django-spurl by Jamie Matthews
django-urltags by Calloway Project/Corey Oordt
the add_query_param filter in django-rest-framework by Tom Christie
On GitHub:
update_querystring by David Gouldin

Getting #permalink decorator to work with django generic views?

Maybe I am missing something, but according to the django docs (1.2), I have setup my URLS models exactly as specified to ensure I am not hard-coding urls returned for get_absolute_url.
Here's what I have:
in urls.py
urlpatterns = patterns('django.views.generic.list_detail',
url(r'^$','object_list',
{ 'queryset': product.objects.all(),
'template_name': 'products/list.html',
},
name='product_list'),
url(r'^(?P<slug>[-\w]+)/$','object_detail',
{ 'queryset': product.objects.all(),
'template_name': 'products/detail.html',
},
name='product_detail'),
)
in models.py
#models.permalink
def get_absolute_url(self):
return ('product_detail', (), {'slug': str(self.slug)})
The method returns an empty string in the templates, and from the shell it gives an error.
NoReverseMatch: Reverse for 'product_detail' with arguments '()' and keyword arguments '{'slug': 'dd-d--'}' not found.
This should resolve should it not, since urls.py has a name : product_detail?
Syntax seems to be correct, are you sure your urls.py gets included? Try stepping in debuggin in view code and use reverse function first to generate the url.
My blind guess would be, something is wrong with your urls.py file in general.
Try changing this line:
url(r'(?P<slug>[-\w]+)/^$','object_detail',
to
url(r'^(?P<slug>[-\w]+)/$','object_detail',
Carret (^) stands for beginning of the line, so it is illogical in the context you wrote it since it means the line has content before it even begins.

Django - reversing wrapped view functions

I am trying to incorporate django-schedule into my project. Django-schedule's source is here. I don't like the urls, because they all capture a slug. My project will only allow one calendar per user, so it doesn't make sense to capture the slug. So, I wrapped the django-schedule views like this (look up the slug using the current user, and pass it to django-schedule's views):
from schedule.views import calendar_by_periods
from schedule.models import Calendar
from schedule.periods import Month
def cal_by_periods_wrapper(view):
def new_view(request, *args, **kwargs):
kwargs['calendar_slug'] = Calendar.objects.get_calendars_for_object(obj=request.user, distinction="owner")[0].slug
return view(request, *args, **kwargs)
return new_view
And here is the relevant section from urls.py:
urlpatterns = patterns('',
url(r'^$',
cal_by_periods_wrapper(calendar_by_periods),
name = "month_calendar",
kwargs={'periods': [Month], 'template_name': 'schedule/calendar_month.html'}),
This works fine until it hits one of the template tags included with django-schedule, prev_url:
#register.simple_tag
def prev_url(target, slug, period):
return '%s%s' % (
reverse(target, kwargs=dict(calendar_slug=slug)),
querystring_for_date(period.prev().start))
This function raises:
TemplateSyntaxError at /teacher/calendar/
Caught an exception while rendering: Reverse for 'month_calendar' with arguments
'()' and keyword arguments '{'calendar_slug': u'asdf'}' not found.
How can I wrap this view and still make the reverse call work?
This has nothing to do with wrapping the function. It's just that you no longer have a URL with the name 'month_calendar' which takes a 'calendar_slug' argument. Either define one in your urlconf, or edit the templatetag.
Edit after comment Yes but the 'reverse' call is still passing a slug argument, and there's no 'month_calendar' url which takes one, so the reverse match fails.