Django: Views within views - python

This may seem very basic, but, though I can guess, how do you make a view within a view, or more accurately, a dynamic template within a dynamic template. You see, I have these blocks of html which contain stats on certain things. How would I create a view that returned one of these boxes so another view could insert them into a template block? Is it "ok" to just have a function which returns it, or do I "have to" follow the same functionName(request) thing instead of functionName(info1, info2, info3) like a normal function. This seems like such a common thing that there would be some sort of standard.

This is exactly what custom template tags - in particular inclusion tags - are for.

If I understand you, you're basically talking about pre-populating the template context. Basically, you want a common bit of context to be present in a number of views, but you don't want to repeat yourself for each view. Using function-based views, the best way is to simply have generic method that takes care of this:
def add_some_context(context={}):
context['foo'] = 'bar'
return context
def view1(self, request):
context = {
'something1': 'blah',
}
return render_to_response('template1.html', add_some_context(context), context_instance=RequestContext(request))
def view2(self, request):
context = {
'something2': 'blah',
}
return render_to_response('template2.html', add_some_context(context), context_instance=RequestContext(request))
Both views will have a foo context variable you can use, then. Doing it with class-based views, you can create a mixin class:
class MyViewMixin(object):
def get_context_data(self, **kwargs):
context = super(MyViewMixin, self).get_context_data(**kwargs)
context['foo'] = 'bar'
return context
class MyView1(MyViewMixin, DetailView):
...
class MyView2(MyViewMixin, ListView):
...
When it comes time to add this to the actual template, you can have each view's template inherit from a template that implements the foo context variable in some way.
If it's something that should be applied to every view, then a context processor is more appropriate, but if it's just for a handful of views, then these two methods will serve you well.

Related

How to avoid repeated code in views in Django?

I have several function based views in a django project, and I noticed that they have some repeated code, in fact, they all do the same thing:
def my_view(request):
form = MyForm(request.POST or None)
if requqest.POST:
if form.is_valid():
do_somethin()
and_something_else()
return redirect('another:page')
return render(request, 'my/tempalate.html', {'form': form})
The only thing that is different is the url where the user is redirected to in case of a succcesful form validation, the template, and maybe the form in the future.
Is it a good idea to use something like this to avoid that repetition?:
def a_view(request, success_redirect_url, template):
form = MyForm(request.POST or None)
if request.POST:
if form.is_valid():
do_something()
and_something_else()
return redirect(success_redirect_url)
return render(request, template, {'form': form})
and then reuse it in other views that have the repeated code? like:
def my_view1(request, url='another_page', template='my/template.html'):
return a_view(request, url, template)
Typically such patterns are defined in class-based views where one can use inheritance to override only some parts of the code flow.
Class-based views
Your view for example looks quite similar to a FormView [Django-doc]. Indeed, we can define a view with:
# app_name/views.py
from django.urls import reverse_lazy
from django.views.generic import FormView
class MyView(FormView):
template_name = 'my/template.html'
success_url = reverse_lazy('another_page')
form_class = MyForm
def form_valid(self, form):
do_somethin()
and_something_else()
return super().form_valid(form)
Here the class-based view has implemented a handler for a POST request that will first construct the form, then check if that form is valid, and if it is invalid rerender the template with the form that now contains the errors. It thus minimizes the amount of code that one has to write to handle a simple form.
Such views also explain clearly what they are doing. A CreateView for example explains by its name that it is used to create new objects, it will thus trigger the .save() method of the form it is operating on. A DeleteView on the other hand makes it clear that a POST request to that view will delete an object.
You can also override the attributes in the urls.py by specifying a value in the .as_view(…) [Django-doc] call:
# app_name/urls.py
from app_name.views import MyView
from django.urls import path
urlpatterns = [
# ⋮,
path('some/path/', MyView(template_name='other/template.html'), name='some-name'),
# ⋮
]
A class-based function thus acts as a template method pattern
Decorators
Another way to do this is to work with decorators that implement small pieces of logic that run before/after a call to the function-based view, and can alter the request/response, or decide to raise an error instead of calling the view.
For example the #require_http_methods(…) decorator [Django-doc] [GitHub] is implemented to first check if the method is one of the listed ones. This is implemented as:
def require_http_methods(request_method_list):
# ⋮
def decorator(func):
#wraps(func)
def inner(request, *args, **kwargs):
if request.method not in request_method_list:
response = HttpResponseNotAllowed(request_method_list)
log_response(
'Method Not Allowed (%s): %s', request.method, request.path,
response=response,
request=request,
)
return response
return func(request, *args, **kwargs)
return inner
return decorator
here the decorator thus checks if the request.method is a member of the request_method_list. If that is not the case, it will return a HTTP 405 response, and specify that that method is not allowed.
While Django offers a lot of decorators, most decorators have a mixin counterpart for a class-based views, and some are implemented already in the View class. For example if the View does not contains a get method, then it will return a HTTP 405 response, so here the required_http_method is not needed as a mixin/decorator for a class-based view.
Skeleton functions
You can implement a view function and use parameters instead to pass values. Usually however this will not be as flexible as a class-based view: it is rather easy to pass some parameters, but it is less useful to specify behavior in a pattern: in that case you need to pass a reference to a function, but then the question arises what parameters should be passed to that.
For example if we want to make a function that renders the template, we can work with a view that looks like:
from django.shortcuts import render
def render_some_template(request, parameter, context_generator, template='our/template.html'):
context = context_generator()
return render(request, template, context)
but perhaps the context_generator function should be called together with the parameter? or perhaps know what template will be rendered. This is one of the reasons why altering code flow is usually done with a class-based view, and less with a function-based view.
While a function-based view can work with a skeleton function, it is usually less exendible than the class-based counterpart. Django's builtin apps (the ones defined in the django.contrib module) are moving mainly towards class-based views, since it is easier to extend these.
You can do a lot better if just give a name to any button wich lunch this function:
<button name='lukaku'>
<button name='ronaldo'>
then into the view check for the name
if form.get('lukaku'):
do something
if form.get('ronaldo'):
do other thing
and so on. this can be limitless

Django docs -- CBVs: Why not just define a get() method that takes an argument from a URL? [duplicate]

I've been learning Django and one source of confusion I have is with class based views and when to override the get method. I've looked through the documentation and it explains what get does but it doesn't explain when I should override get.
I originally created a view this way:
class ExampleView(generic.ListView):
template_name = 'ppm/ppm.html'
paginate_by = 5
def get(self, request):
profiles_set = EmployeeProfile.objects.all()
context = {
'profiles_set': profiles_set,
'title': 'Employee Profiles'
}
return render(request, self.template_name, context)
But I was recently told that my code was simple of enough for the default implementation, and that all I needed was this:
class ExampleView(generic.ListView):
model = EmployeeProfile
template_name = 'ppm/ppm.html'
So my Question is this: In what scenario/circumstance should I override the get method?
If you are using the builtin generic views, then you should rarely have to override get(). You'll end up either duplicating lots of functionality, or break features of the view.
For example, the paginate_by option will no longer work in your view, because you are not slicing the queryset in your get() method.
If you are using a generic class based view like ListView, you should try to override specific attributes or methods where possible, rather than overriding get().
The advantage of your view which overrides get() is that it's very clear what it does. You can see that the view fetches a queryset, includes it in a context, then renders the templates. You don't need to know about ListView to understand the view.
If you like the explicitness of overriding get() subclass View instead. You aren't using any of the features of ListView, so it doesn't make sense to subclass it.
from django.views.generic import View
class ExampleView(View):
template_name = 'ppm/ppm.html'
def get(self, request):
...
You should override the get method when you specifically want to do something other than the default view does. In this case, your code isn't doing anything other than rendering the template with the list of all EmployeeProfile objects, which is exactly what the generic ListView would do.
You might override it if you want to do something more complicated. For example, maybe you want to filter based on a URL parameter:
class ExampleView(generic.ListView):
template_name = 'ppm/ppm.html'
def get(self, request):
manager = request.GET.get('manager', None)
if manager:
profiles_set = EmployeeProfile.objects.filter(manager=manager)
else:
profiles_set = EmployeeProfile.objects.all()
context = {
'profiles_set': profiles_set,
'title': 'Employee Profiles'
}
return render(request, self.template_name, context)

When to use get, get_queryset, get_context_data in Django?

I recently learned that you should override the get method when you specifically want to do something other than what the default view does:
class ExampleView(generic.ListView):
template_name = 'ppm/ppm.html'
def get(self, request):
manager = request.GET.get('manager', None)
if manager:
profiles_set = EmployeeProfile.objects.filter(manager=manager)
else:
profiles_set = EmployeeProfile.objects.all()
context = {
'profiles_set': profiles_set,
'title': 'Employee Profiles'
}
That's simple enough, but when should I use get_queryset or get_context_data over get? To me it seems like they basically do the same thing or am I just missing something? Can I use them together? This is a major source of confusion for me.
So to reiterate: In what cases would I use get over get_queryset or get_context_data and vise versa?
They indeed do different things.
get()
This is a top-level method, and there's one for each HTTP verb - get(), post(), patch(), etc. You would override it when you want to do something before a request is processed by the view, or after. But this is only called when a form view is loaded for the first time, not when the form is submitted. Basic example in the documentation. By default it will just render the configured template and return the HTML.
class MyView(TemplateView):
# ... other methods
def get(self, *args, **kwargs):
print('Processing GET request')
resp = super().get(*args, **kwargs)
print('Finished processing GET request')
return resp
get_queryset()
Used by ListViews - it determines the list of objects that you want to display. By default, it will just give you all for the model you specify. By overriding this method you can extend or completely replace this logic. Django documentation on the subject.
class FilteredAuthorView(ListView):
template_name = 'authors.html'
model = Author
def get_queryset(self):
# original qs
qs = super().get_queryset()
# filter by a variable captured from url, for example
return qs.filter(name__startswith=self.kwargs['name'])
get_context_data()
This method is used to populate a dictionary to use as the template context. For example, ListViews will populate the result from get_queryset() as author_list in the above example. You will probably be overriding this method most often to add things to display in your templates.
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['page_title'] = 'Authors'
return data
And then in your template, you can reference these variables.
<h1>{{ page_title }}</h1>
<ul>
{% for author in author_list %}
<li>{{ author.name }}</li>
{% endfor %}
</ul>
Now to answer your main question, the reason you have so many methods is to let you easily stick your custom logic with pin-point accuracy. It not only allows your code to be more readable and modular, but also more testable.
The documentation should explain everything. If still not enough, you may find the sources helpful as well. You'll see how everything is implemented with mixins which are only possible because everything is compartmentalized.
Let's look at the default implementation of ListView's get method:
https://github.com/django/django/blob/92053acbb9160862c3e743a99ed8ccff8d4f8fd6/django/views/generic/list.py#L158
class BaseListView(MultipleObjectMixin, View):
"""
A base view for displaying a list of objects.
"""
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if (self.get_paginate_by(self.object_list) is not None
and hasattr(self.object_list, 'exists')):
is_empty = not self.object_list.exists()
else:
is_empty = len(self.object_list) == 0
if is_empty:
raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.")
% {'class_name': self.__class__.__name__})
context = self.get_context_data()
return self.render_to_response(context)
You will notice that get_queryset gets called in the first line. You can simply overwrite that if you just want to return your model's queryset after applying some filtering/ordering etc.
You don't need to overwrite the whole get method for that because you will be missing on all this provided functionality i.e. pagination, 404 checks etc.
get_context_data merges the resulting queryset together with context data like querystring parameters for pagination etc.
What I would recommend would be to check with django's source every once in a while and try to understand it a little bit so that you can recognize the most appropriate method you can overwrite/replace.

How does class based view with multiple methods work with urls in django?

I have a created a view class "class Demo", which has 3 functions
def update_time()
def get_context()
def before_response()
urls.py : url(r'^demo/$', Demo.as_view(),name='demo_class'),
When i'll enter url /demo/ how will it determine which function to call from "class Demo" ?
Because Django’s URL resolver expects to send the request and associated arguments to a callable function, not a class, class-based views have an as_view() class method which serves as the callable entry point to your class. The as_view entry point creates an instance of your class and calls its dispatch() method. dispatch looks at the request to determine whether it is a GET, POST, etc, and relays the request to a matching method if one is defined, or raises HttpResponseNotAllowed if not.
just read the docs
Basically class based views are recommended when you need to handle both get and post requests at one point. For example in get method of class Register, you can render the registration form and in its post method, you can handle the form submission. If its a get request it will automatically invoke the get() method in the class, same for post request. Also you can write any common code in the dispatch() method which will be invoked for every request.eg:
class Register(View):
def dispatch(self, *args, **kwargs):
'''
common code here
'''
return super(Register, self).dispatch(*args, **kwargs)
def get(self, request):
registration_form = RegistrationForm()
return render(request, 'new.html', { 'form': registration_form })
def post(self, request):
registration_form = RegistrationForm(request.POST or None)
if registration_form.is_valid():
#save form
return HttpResponseRedirect(reverse('success-show'))
return render(request,new.html', { 'form': registration_form })
For references you can check this website.
You need to subclass a class based views, and depending on that it will have one or another method.
For example TemplateView renders a template you pass in the template_name attribute.
All class based views care about is that the attributes needed to work properly are setted. That is done via different methods. You can check the django's documentation for specifics.
For example, if you want to render a form in your template view, you will need to pass the form in the context, so you can override get_context_data() like:
def get_context_data(self, **kwargs):
context = super(DemoClass, self).get_context_data(**kwargs)
context['form'] = MyForm()
return context
There are different methods to handle different things, like querysets, objects, etc.
They are not complicated, but they are specific. If a class based view does not fit what you need, it may be easier to implement the functionality from a more general view (View, TemplateView) than forcing a more specific one to do things it is not intended for.
slightly change the url
add numbers one to three in url and put the condition in your view.
Ex.
url(r'^abc/(?P<newid>.*)$', 'class_demo'),
so your url will be like abc/1 or abc/2 or abc/3
view
def class_demo(requests, newid):
if newid==1:
update_time()
elif newid==2:
get_context()

Accessing URL variables in Django 1.5 class-based view

I'm migrating a project from Django 1.2 to Django 1.5. The project used function-based views such as this:
def notecard_product(request, stockcode):
if request.user.is_authenticated():
liked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=True, user=request.user)
unliked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=False, user=request.user)
extra_context = {"liked" : liked, "unliked":unliked}
else:
extra_context = {"liked" : [0], "unliked": [0]}
return object_detail(request, queryset=Product.objects.live(),
object_id=stockcode,
extra_context=extra_context,
template_name='products/notecard.html', template_object_name='notecard_product')`enter code here`
In this excerpt, stockcode is captured from the URL and used to determine object_id. So I'm wondering how I would do this in a class-based view. This is what I have so far:
class NotecardProductListView(ListView):
queryset=Product.objects.live()
pk=self.kwargs['stockcode']
template_name='products/notecard.html'
context_object_name='notecard_product'
def get_context_data(self, **kwargs):
context = super(BooksListView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated():
liked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=True, user=self.request.user)
unliked = Recommendation.objects.values_list('product_id',flat=True).filter(recommended=False, user=self.request.user)
extra_context = {"liked" : liked, "unliked":unliked}
else:
extra_context = {"liked" : [0], "unliked": [0]}
context.update(extra_context)
return context
pk is the new name for the old object_id kwarg. Obviously, this code doesn't work, because I can't access self outside of a function. But I'm not really sure how to do this. I need to set pk to something in the keyword arguments, but can't find a way to do this, as pk needs to be set in the class body outside of any functions. I also don't really have a way to experiment and try things, because the entire project is broken right now due to deprecated function calls.
Thanks!
I'm not sure where you got the idea that pk is the new name for object_id, nor why you think that you need to set it to a value per request. The point of the class-level attributes in class-based views is that they are set per view class, not per instance: they refer to the place the view will go to look up the value, not the actual value itself.
Your first mistake is that the equivalent of the old object-detail view is, not surprisingly, DetailView, not ListView. As the documentation shows, ListView gets the ability to show an object detail via its inheritance from the SingleObjectMixin. That mixin expects a class-level attribute called pk_url_kwarg, which is the name of the argument captured from the URL which identifies the object's PK: in your case, this is the string 'stockcode'. The instance itself takes care of looking up that value in any particular request, you don't need to do it.

Categories