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'm starting to use class based views for an application I'm creating but I'm nots sure how it works.
What I need is to have three different templates, and each template will show different information depending on a model field. My question is if there's a way to have only one class view that can render three different html templates with 3 different contexts, or if I need to create 3 different classes.
Using function based views, I would just do this:
# def humanResourcesView(request):
# context = {
# 'data' : Document.objects.all().filter(documentType='humanResources'),
# }
# return render(request, 'main/hr.html', context)
# #view to display training documents after click
# def trainingView(request):
# context = {
# 'data' : Document.objects.all().filter(documentType='training'),
# }
# return render(request, 'main/training.html', context)
# #view to display resource documents after click
# def reportsView(request):
# context = {
# 'data' : Document.objects.all().filter(documentType='reports')
# }
# return render(request, 'main/reports.html', context)
But I'm not sure how it works with class based views. Currently I have this, which renders and filters data correctly for one template, but I don't know how to do multiple templates. Do I need to create 3 different classes?
class DocumentView(View):
def get(self, request, *args, **kwargs):
reports = Document.objects.all().filter(documentType="reports")
context = {
'reports' : Document.objects.all().filter(documentType='reports')
}
return render(request, 'documents/reportsDocs.html', context)
Is there a way to only have one class, and pass a certain context depen
You would need to inherit from TemplateView
and override the get_template_names method to return your conditional based template.
And you would override get_context_date to fetch the data accordingly.
from django.views.generic import TemplateView
class DocumentView(TemplateView):
def get_template_names(self):
pass
def get_context_data(self, **kwargs):
pass
how can i pass a context variable in a class. i know that i would use the render if i was showing my template from a function. and then i could just pass my context variable as part of the render. But how do i pass a context variable to html if i am using a class to show the template.
i have tried putting a function into my class but it has not worked.
views.py
class hithere(ListView):
model = Datadata
template_name = 'index.html'
def whatsup(request):
context = {}
context['my_string'] = "this is my sring"
return render(request, context)
Index.html
<h1> {{ my_string }} </h1>
You can override the .get_context_data(…) method [Django-doc]:
class hithere(ListView):
model = Datadata
template_name = 'index.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['my_string'] = 'this is my string'
return context
But perhaps more convenient is to define a method:
class hithere(ListView):
model = Datadata
template_name = 'index.html'
def my_string(self):
return 'this is my string'
and render this with:
{{ view.my_string }}
Note: normally a Django models, just like all classes in Python are given a name in PerlCase, not snake_case, so it should be: HitHereView instead of hithere.
I created a class representing an input widget and I'd like to use if directly in the template. However, whenever I pass it to the template it gets escaped.
class Widget:
def render(self):
Markup('<input type="text">')
def __str__(self):
return self.render()
def __repr__(self):
return self.render()
widget = Widget()
widget # <input type="text">
tpl = Template('{{ field }}', autoescape=True)
tpl.render(field=widget) # '<input type="text">'
tpl.render(field=str(widget)) # '<input type="text">'
Is it possible to use the widget directly without wrapping it in str or calling render from within the template? Is there any magic method which I need to override?
After digging through jinja2 and markupsafe source code I found that my widget needs to implement __html__ magic method which returns the "safe" string.
def __html__(self):
return self.render()
I have a Django model, Note, which has a class-based view. It is supposed to return a JSON object upon the appropriate query.
Before returning the object, however, I would like to check that the user field in the note object matches the user currently logged in. (Users should not be able to access Note objects that are not their own.) To do this, I tried rewriting the get() method, calling on self.retrieve() to inspect the object before returning it:
class NoteDetail(generics.RetrieveUpdateDestroyAPIView):
model = Note
serializer_class = NoteSerializer
permission_classes = (permissions.IsAuthenticated,)
renderer_classes = (JSONRenderer,)
def get(self, request, *args, **kwargs):
current_user = User.objects.get(pk=self.request.user.id)
note = self.retrieve(request, *args, **kwargs)
if note.author is current_user:
return note
else:
raise PermissionDenied('Note does not belong to authenticated user.')(author=current_user)
However, this returns a ContentNotRenderedError when run: The response content must be rendered before it can be accessed.
Is there a way for me to check the object before returning it? Must I find a workaround?
One potential workaround is to redefine get_queryset(), rather than get() or get_object(). get_queryset() is the function that returns all objects of the relevant model; get_object() narrows down among these given the argument pk.
By overriding get_queryset(), you restrict the potential objects that get_object() can pick. Thus the set is already filtered at the time get() is called.
def get_queryset(self):
current_user = User.objects.get(pk=self.request.user.id)
# Must filter by author to prevent making everyone's notes public
queryset = Note.objects.filter(author=current_user)
return queryset
I have a Scrib model and a template which gets Scrib.objects.all() stored into scribs
In the template, I'd like to access to the verbose name of the model like:
<h1>{{ scribs.model.verbose_name }}</h1>
Is it possible or do I have to add the Scrib handler to the context ?
You can't access the verbose_name directly from the template. From what I see you got three options.
Option one (simplest). Assign the verbose name in your controller and then access it from the template:
# in controller
render_to_response('template.html', {'scrib_verbose_name': Scrib._meta.verbose_name})
# in a view template.html
Verbose name of a Scrib model: {{ scrib_verbose_name }}
Option two: write yourself a view helper that will return the verbose_name (or other field from _meta class) for a given class.
Update Third option (a hat tip to Uku Loskit) - define a method on a scrib model that returns the meta object (or any particular field from it).
# method in a Scrib model
def meta(self):
return self._meta
# later on in a template - scrib is a instance of Scrib model
<h1>{{ scrib.meta.verbose_name }}</h1>
Update2 If you insist on directly accessing verbose name from the scribs (which is a result of Scrib.objects.all()), then you can do stuff like:
scribs = Scrib.objects.all()
scribs.verbose_name = Scrib._meta.verbose_name
# in a template you can now access verbose name from a scribs variable
{{ scribs.verbose_name }}
Update3 Yet another way to go is using model inhertinace to be able to access the verbose name from instance of any model that inherit from our custom one.
# base model (inherits from models.Model)
class CustomModel(models.Model):
def meta(self):
return self._meta
class Meta:
abstract = True
# Scrib now inherit from CustomModel
class Scrib(CustomModel):
# do any stuff you want here ...
Scrib now inherit from CustomModel that provides us with property meta. Any model that will inherit from CustomModel class is going to have this property. It's the cleanest and most flexible solution.
I want to do that as well, I suppose another solution would be a template filter:
from django import template
register = template.Library()
#register.filter
def verbose_name(value):
return value._meta.verbose_name
#register.filter
def verbose_name_plural(value):
return value._meta.verbose_name_plural
Then in the template:
1 {{ object|verbose_name }}, 2 {{ object|verbose_name_plural }}
1 scrib, 2 scribs
Alternatively to WTK's suggestion you could define a method for the Scrib model in your models.py like this:
def get_verbose_name(self):
return self._meta.verbose_name
# in templates
{{ scrib_instance.get_verbose_name }}