In my url conf, I have several URL's which have the same named parameter, user_id.
Is it possible to access this parameter either in a middleware - so I can generically pass it on to the context_data - or in the template itself?
Sample URL conf to illustrate the question:
url(r'^b/(?P<user_id>[0-9]+)/edit?$', user.edit.EditUser.as_view(), name='user_edit'),
url(r'^b/(?P<user_id>[0-9]+)/delete?$', user.delete.DeleteUser.as_view(), name='user_delete')
For class based views, the view is already available in the context, so you dont need to do anything on the view side. In the template, just do the following:
{{ view.kwargs.user_id }}
See this answer
If you need this data in the template, just override your view's get_context_data method:
class MyView(View):
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['user_id'] = self.kwargs.get('user_id')
return context
For function based views:
template
{% url 'view' PARAM=request.resolver_match.kwargs.PARAM %}
views.py
def myview(request, PARAM):
...
Django 2.2
Related
I want to pass the previous URL in a context variable for a generic view:
class PostDeleteView(DeleteView, LoginRequiredMixin):
previous_url = self.request.META.get('HTTP_REFERER')
...
However, I can't access either self or request. How do I go about this?
For example, if you wanted to use the tag {{ previous_url }} in your templates you would override the get_context_data() method.
Normally you could also pass extra context using the top level attribute extra_context but the request object isn't available yet so you will be forced to override.
class PostDeleteView(LoginRequiredMixin, DeleteView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['previous_url'] = self.request.META.get('HTTP_REFERER')
return context
There's a site called classy class based views that breaks down all the methods used in Django's built in class based views so you can get an idea of how everything is put together behind the scenes.
Actually I just remembered an easier solution, if you have the request context processor enabled in TEMPLATES in your project settings then you can access {{ request }} directly in your templates.
'context_processors': [
...
'django.template.context_processors.request',
...
]
I'm using Django-registration-redux and I want give more data to a view to render my base template. I read the example in doc.
My url.py:
class MyPasswordChangeView(PasswordChangeView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# context['book_list'] = Book.objects.all() # example in doc
context_dict = services.get_base_data_for_views(request)
return context_dict
urlpatterns = [
...
path('accounts/password/change/', MyPasswordChangeView.as_view(
success_url=reverse_lazy('auth_password_change_done')), name='auth_password_change'),
...
]
I have the extra data in services.py but this code gives error:
name 'request' is not defined
So context_dict isn't defined. Where can I take my request from? Mainly I need the user (but print(user)= 'user' is not defined). Or should I write another function?
In methods of Django class based views, you can access the request with self.request.
class MyPasswordChangeView(PasswordChangeView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context_dict = services.get_base_data_for_views(self.request)
return context_dict
Therefore you can access the user with self.request.user. Normally you would want to use login_required or LoginRequiredMixin so that only logged-in users can access the view, but in your case PasswordChangeView takes care of that for you.
say I have:
class MyCreate(CreateView):
template_name = 'template.html'
success_url = reverse_lazy('blabla')
form_class = MyForm
And suppose in my template I want to add a back button. The back will lead me to the same page as success_url. My solution was to override get_context_data in MyCreate class and add {'back': self.get_success_url()} to the context.
The implications is that I have more CreateViews and I had to create a ContextMixin for this back button. Is there any other easier solution? something like accessing success_url directly in my template?
Thanks
As we can see in django (1.7) implementation of ContextMixin, we must have access to view instance from our templates:
def get_context_data(self, **kwargs):
if 'view' not in kwargs:
kwargs['view'] = self
return kwargs
So you can access to success_url in templates:
{{ view.get_success_url }}
In my case using Django 1.10.3 the way to get it working was like this:
view:
from django.urls.base import reverse_lazy
class FooCreateView(CreateView):
success_url = reverse_lazy('name-of-some-view')
template:
{{ view.success_url }}
The try of using {{ view.get_success_url }} was leading to:
AttributeError 'NoneType' object has no attribute '__dict__'
With django-allauth, I am forcing a new user to fill out additional profile information on signup using a custom ACCOUNT_SIGNUP_FORM.
settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'profiles.signup.ProfileSignupForm'
SOCIALACCOUNT_AUTO_SIGNUP = False
This ProfileSignupForm is then rendered in a modified allauth/templates/socialaccount/signup.html template. This modified template renders the logo of the new user's company that is defined in the new user's session (I used an invitation link that first goes to a RedirectView, writes into the session, and then forwards to the new signup).
signup.html
<html>
<body>
<img src="{{ logo }}" />
{% crispy form %}
</body>
</html>
How can I pull the company logo from my session and pass it to my template without forking the repository and modifying the SignUp View?
That approach would look like this:
class SignupView(RedirectAuthenticatedUserMixin, CloseableSignupMixin, FormView):
def dispatch(self, request, *args, **kwargs):
...
self.company = request.session.get('company')
...
def get_context_data(self, **kwargs):
...
context['logo'] = company.logo
...
Either you can follow the above mentioned way to Inherit the View and Define custom url for Signup to use your view.
Or
you car directly access company logo in your template as:
{{ request.session.company.logo }}
This can be done because request is available as a context variable in Templates if rendered with RequestContext instance.
you can inherit SignupView directly in your code instead of forking and modifying the original SignupView.
class MySignupView(SignupView):
def dispatch(self, request, *args, **kwargs):
...
self.company = request.session.get('company')
...
return super(MySignupView, self).dispatch(request, *args, *kwargs)
def get_context_data(self, **kwargs):
context = super(MySignupView, self).get_context_data(**kwargs)
context['logo'] = self.company.logo
return context
Then using MysignupView.as_view() in the urls.py.
Each time a request is made to my app, I am using middleware to retrieve and store a 'Page' object which has information relevant that particular page. I am storing a reference to this object in the request object, here is an example:
class PageMiddleware(object):
def process_request(self, request):
if not hasattr(request, 'page'):
request.page = Page.objects.get(slug=<slug>)
return None
It works well enough, but I want to access this object in a template tag. Template tags only have a reference to 'context' thought, meaning I am unable to see my Page object.
I know I can use a custom context processor for this but that means modifying the settings file further and I'd like to try and keep this app as encapsulated as possible. I noticed, for example, that the Debug Toolbar app manages to append data to the template context without modifying the TEMPLATE_CONTEXT_PROCESSORS.
In short, I want to access my Page object in a template tag ideally by just using middleware. Any ideas?
Edit: I am using a standard template tag, with the following class:
class GetPageContentNode(Node):
def __init__(self, key):
self.key = key
def render(self, context):
return context['request'].page
Have a look at this, you can get access to the request object (and your object) by passing takes_context when registering the template tag
Access request in django custom template tags
Have a search for "takes_context" on this page:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#registering-the-tag
Call every render_to_response with a context_instance parameter, like:
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
EDITED as sugested by Daniel Roseman:
And add django.core.context_processors.request to your TEMPLATE_CONTEXT_PROCESSORS settings.
Try this:
class GetPageContentNode(Node):
def __init__(self, key):
self.key = key
def render(self, context):
request = template.Variable('request').resolve(context) # here's the magic!
return request.page