Class views in Django - python

Django view points to a function, which can be a problem if you want to change only a bit of functionality. Yes, I could have million keyword arguments and even more if statements in the function, but I was thinking more of an object oriented approach.
For example, I have a page that displays a user. This page is very similar to page that displays a group, but it's still not so similar to just use another data model. Group also has members etc...
One way would be to point views to class methods and then extend that class. Has anyone tried this approach or has any other idea?

I've created and used my own generic view classes, defining __call__ so an instance of the class is callable. I really like it; while Django's generic views allow some customization through keyword arguments, OO generic views (if their behavior is split into a number of separate methods) can have much more fine-grained customization via subclassing, which lets me repeat myself a lot less. (I get tired of rewriting the same create/update view logic anytime I need to tweak something Django's generic views don't quite allow).
I've posted some code at djangosnippets.org.
The only real downside I see is the proliferation of internal method calls, which may impact performance somewhat. I don't think this is much of a concern; it's rare that Python code execution would be your performance bottleneck in a web app.
UPDATE: Django's own generic views are now class-based.
UPDATE: FWIW, I've changed my opinion on class-based views since this answer was written. After having used them extensively on a couple of projects, I feel they tend to lead to code that is satisfyingly DRY to write, but very hard to read and maintain later, because functionality is spread across so many different places, and subclasses are so dependent on every implementation detail of the superclasses and mixins. I now feel that TemplateResponse and view decorators is a better answer for decomposing view code.

I needed to use class based views, but I wanted to be able to use the full name of the class in my URLconf without always having to instantiate the view class before using it. What helped me was a surprisingly simple metaclass:
class CallableViewClass(type):
def __call__(cls, *args, **kwargs):
if args and isinstance(args[0], HttpRequest):
instance = super(CallableViewClass, cls).__call__()
return instance.__call__(*args, **kwargs)
else:
instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
return instance
class View(object):
__metaclass__ = CallableViewClass
def __call__(self, request, *args, **kwargs):
if hasattr(self, request.method):
handler = getattr(self, request.method)
if hasattr(handler, '__call__'):
return handler(request, *args, **kwargs)
return HttpResponseBadRequest('Method Not Allowed', status=405)
I can now both instantiate view classes and use the instances as view functions, OR I can simply point my URLconf to my class and have the metaclass instantiate (and call) the view class for me. This works by checking the first argument to __call__ – if it's a HttpRequest, it must be an actual HTTP request because it would be nonsense to attept to instantiate a view class with an HttpRequest instance.
class MyView(View):
def __init__(self, arg=None):
self.arg = arg
def GET(request):
return HttpResponse(self.arg or 'no args provided')
#login_required
class MyOtherView(View):
def POST(request):
pass
# And all the following work as expected.
urlpatterns = patterns(''
url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
url(r'^myview2$', myapp.views.MyView, name='myview2'),
url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)
(I posted a snippet for this at http://djangosnippets.org/snippets/2041/)

If you're simply displaying data from models, why not use the Django Generic Views? They're designed to let you easy show data from a model without having to write your own view and stuff about mapping URL paramaters to views, fetching data, handling edge cases, rendering output, etc.

You can always create a class, override the __call__ function and then point the URL file to an instance of the class. You can take a look at the FormWizard class to see how this is done.

Unless you want to do something a little complex, using the generic views are the way to go. They are far more powerful than their name implies, and if you are just displaying model data generic views will do the job.

Sounds to me like you're trying to combine things that shouldn't be combined. If you need to do different processing in your view depending on if it's a User or Group object you're trying to look at then you should use two different view functions.
On the other hand there can be common idioms you'd want to extract out of your object_detail type views... perhaps you could use a decorator or just helper functions?
-Dan

Generic views will usually be the way to go, but ultimately you're free to handle URLs however you want. FormWizard does things in a class-based way, as do some apps for RESTful APIs.
Basically with a URL you are given a bunch of variables and place to provide a callable, what callable you provide is completely up to you - the standard way is to provide a function - but ultimately Django puts no restrictions on what you do.
I do agree that a few more examples of how to do this would be good, FormWizard is probably the place to start though.

If you want to share common functionality between pages I suggest you look at custom tags. They're quite easy to create, and are very powerful.
Also, templates can extend from other templates. This allows you to have a base template to set up the layout of the page and to share this between other templates which fill in the blanks. You can nest templates to any depth; allowing you to specify the layout on separate groups of related pages in one place.

You can use the Django Generic Views. You can easily achieve desired functionality thorough Django generic Views

Related

What are the differences between Generics, Views, Viewsets and Mixins in Django?

I am new to Django and Django-Rest. I am confused about when I should use these? what are their advantages and disadvantages? I have only seen this- http://www.cdrf.co
The only thing I know is there are a lot of ways to do 1 thing. But this is totally unclear to me.
In Django, these four terms we use frequently for different purposes in the projects. I have tried to collect and share the actual meaning with the links to details description of each term. Please check if you find these helpful.
Generic views:
“Django’s generic views... were developed as a shortcut for common usage patterns... They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to repeat yourself.”
— Django Documentation
Read more details
Views:
A view function, or view for short, is simply a Python function that takes a Web request and returns a Web response. This response can be the HTML contents of a Web page, or a redirect, or a 404 error, or an XML document, or an image . . . or anything, really. The view itself contains whatever arbitrary logic is necessary to return that response. This code can live anywhere you want, as long as it’s on your Python path. There’s no other requirement–no “magic,” so to speak. For the sake of putting the code somewhere, the convention is to put views in a file called views.py, placed in your project or application directory.
Read more details
Viewsets:
Django REST framework allows you to combine the logic for a set of related views in a single class, called a ViewSet. In other frameworks, you may also find conceptually similar implementations named something like 'Resources' or 'Controllers'.
A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as .get() or .post(), and instead provides actions such as .list() and .create().
The method handlers for a ViewSet are only bound to the corresponding actions at the point of finalizing the view, using the .as_view() method.
Read more details
Mixins:
The mixin classes provide the actions that are used to provide the basic view behavior. Note that the mixin classes provide action methods rather than defining the handler methods, such as .get() and .post(), directly. This allows for more flexible composition of behavior.
The mixin classes can be imported from rest_framework.mixins.
Read more details

Is it possible to use the same method for both get and post with webapp2?

There is very little difference in my get and post methods. One way to do this would be to put the common logic in another function and call that in both the get and post methods. But before I do that I wanted to know If I can actually have one function handle both, that'll be really neat.
You can also use a BaseHandler for your handlers. You can put common methods for sessions, login and templates in the BaseHandler.
See this example for sessions or this blog post about webapp2 and templates.
This is a good description of when to use GET vs POST. You can use either, of course, but there are situations where you'd want to use one vs the other. You can use the same methods to process them from within the same class if you wanted to like this:
class MyHandler(webapp2.RequestHandler):
def function_to_handle_requests(self):
# code goes here
def get(self):
self.function_to_handle_requests
def post(self):
self.function_to_handle_requests

Is it possible to call different function of class based views through different actions in template

I am new to django and i ahve gone through all the docs of django. right now if we give some link in template and defined that link in urls.py i.e which view is going to handle that link. like this url(r'^dashboard/gift/$', login_required(CouponPageView.as_view())),
But i have this little doubt can i call different function of a view on clicking different links present in template.
The idea behind a class-based view is not to serve multiple resources (the targets of the links in your template). The idea is that the class-based view implements methods for the various HTTP methods (i.e. get, post, put, delete, head).
So you can server an HTTP GET of a certain URI using the SomeView.get() method, or you can handle a POST to the same resource from the post() method in the same SomeView class. This is helpful to support object oriented code, as the different methods on the object will typically share some resources.
If you want to handle different URL's, write different View classes. If their functionality is similar, use inheritance to prevent code duplication. If their functionality is almost identical, use parameters in the urlpattern.
I think you need to study the URL dispatcher a little more: https://docs.djangoproject.com/en/dev/topics/http/urls/

Generic view with additional parameters (if possible) or context processors to pass extra info to the template?

I have a generic ListView that returns a list of objects.
All was good before I decided to print how many time passed since creation time (not just when the object was created) for every object.
Then I need a piece of code to count it and I need to pass the results to the template.
But now I can't use a generic view.
I thought about context processors, but context processors take only request as a parameter and I need to give it also the id of an object to count the time delta.
So, is there any way to make it using generic views or context processors or I have to code a custom view? Or is there a better way?
UPDATE
Thanks everyone for detailed answers, it will greatly help me in the future.
I learned that the mentioned task can be solved using timesince built-in template tag. Hope it will help someone.
You can override get_context_data and add more data to the context dictionary:
class MyView(ListView):
# ...
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['mydata'] = ...
return context
You can then use mydata in the template.
You can also access context['object_list'] which contains the list of objects that will be displayed in the template.
Simeon's answer is the obvious one if you need to add more stuff in the context for a specific ListView, but you can also use custom templatetags or filters if you need something that doesn't directly depend on the view itself. In you case a simple filter computing the delta from any date or datetime might be the ticket. Extra bonus: you can reuse it on any date in any template without having to change anything in the views...

Class Based Views VS Function Based Views

I always use FBVs (Function Based Views) when creating a django app because it's very easy to handle. But most developers said that it's better to use CBVs (Class Based Views) and use only FBVs if it is complicated views that would be a pain to implement with CBVs.
Why? What are the advantages of using CBVs?
The single most significant advantage is inheritance. On a large project it's likely that you will have lots of similar views. Rather than write the same code again and again, you can simply have your views inherit from a base view.
Also django ships with a collection of generic view classes that can be used to do some of the most common tasks. For example the DetailView class is used to pass a single object from one of your models, render it with a template and return the http response. You can plug it straight into your url conf..
url(r'^author/(?P<pk>\d+)/$', DetailView.as_view(model=Author)),
Or you could extend it with custom functionality
class SpecialDetailView(DetailView):
model = Author
def get_context_data(self, *args, **kwargs):
context = super(SpecialDetailView, self).get_context_data(*args, **kwargs)
context['books'] = Book.objects.filter(popular=True)
return context
Now your template will be passed a collection of book objects for rendering.
A nice place to start with this is having a good read of the docs (Django 4.0+).
Update
ccbv.co.uk has comprehensive and easy to use information about the class based views you already have available to you.
When I started with DJango I never used CBVs because of their learning curve and a bit complex structure. Fast forward over two years, I use FBVs only at few places. Where I am sure the code will be really simple and is going to stay simple.
Major benefit of CBVs and Multiple Inheritence that comes along with them is that I can completely avoid writing signals, helper methods and copy paste code. Especially in the cases where the app does much more than basic CRUD operations. Views with multiple inheritance are multiple times easier to debug that a code with signals and helper methods, especially if it is an unknown code base.
Apart from Multiple inheritence CBVs by provide different methods to do dispatching, retrieving templates, handling different request types, passing template context variables, validating forms, and much more out of the box. These make code modular and hence maintainable.
Some views are best implemented as CBVs, and others are best implemented as FBVs.
If you aren’t sure which method to choose, see the following chart:
SOME WORDS FROM TWO SCOOPS
Tip Alternative Apporach - Staying With FBVs
Some developer prefer to err on the side of using FBVs for most views and CBVs only for views that need to be subclassed. That strategy is fine as well.
Class based views are excellent if you want to implement a fully functional CRUD operations in your Django application, and the same will take little time & effort to implement using function based views.
I will recommend you to use function based views when you are not going to implement any CRUD on your site/application means your intension is to simply render the template.
I had created a simple CRUD based application using class based views which is live. Visit http://filtron.pythonanywhere.com/view/ (will/won't be working now) and enjoy. Then you will know the importance of it.
I have been using FBVs in most of the cases where I do not see a real opportunity of extending views. As documented in the docs, I consider going for CBVs if the following two characteristics suit my use-case.
Organization of code related to specific HTTP methods (GET, POST, etc.) can be addressed by separate methods instead of conditional branching.
Object oriented techniques such as mixins (multiple inheritance) can be used to factor code into reusable components.
Function-Based Views(FBVs) are:
Easy to use but the
Code is not reusable by inheritance.
Recommended to use
Class-Based Views(CBVs) are:
Too much learning curve because it's really complicated
Code is reusable by inheritance.
Not recommended to use (FBVs are much beter)

Categories