I've been wondering lately — what good having the server-side web application generate URLs when the client side code is just as capable? Indeed, there is no way we'd ever want to hard-code the application URL paths inside the Javascript code. So why even entertain the notion?
Speaking in terms of overhead — with each URL on a given page, some CPU expense is incurred when constructing each URL. I'm making a presumption here in assuming URLs are in fact being constructed and not just hard-coded in templates. In reality, the overhead is inconsequential, but in some generic circumstances, I see absolutely no reason why these URL's can't be assembled locally on the user's browser.
Why URLs Are Constructed
It's for the best that URL's passed to the browser by the web application are constructed rather than stored statically. Ad-hoc construction of URLs doesn't solve any problems either. For example, if on one page you're formatting a string that'll be returned as a URL, and on another page, another set of URL construction functionality, it's difficult to establish patterns of reuse. Sure, we're able to share some of this code among our application's components — but why should we have to define this capability ourselves?
Look no further than Django's URL resolution architecture for an example of how URLs are specified in one place and one place only. These are base URLs — they can take on different forms by inserting values into path segments. For instance, search strings or object identities.
The rest of the Django application can construct — resolve in Django-speak — the URL to use. What I really like about this methodology is that URLs are treated just like classes in object oriented programming languages. The URL blueprint is defined once, individual instances of the URL are constructed as many times necessary. Some URL instances are simple — they take no additional attributes. They have no path segments to fill in or no query strings to append. In the case of more complex URL instances, we have the URL resolution framework at our disposal — a consistent approach to instantiate our URL blueprints, passing in any additional details the URL class requires in order to make them unique and identifiable.
The theme here being that URLs can, and should be, a generalized concept — just like other systems we build. We're able to abstract away much complexity into classes, instantiating objects, letting the class machinery take care of eliminating what would be otherwise redundant repetitions of URL construction code. Sticking with the Django URL resolution architecture as the example, because it illustrates so well how URLs can be constructed, consider user interface code. The templates. The Django template system comes with a URL tag to help instantiate URLs directly in the user interface. Again, when templates are rendered, we're injecting URL instances into the template. It's from here that we can follow the logical extension into generic URLs in Javascript.
Javascript And URLs
Javascript can do a lot with URLs that the web application, running on the web server doesn't necessarily need to deal with. But why would we want to use Javascript? Shouldn't we stick with the URL construction kit offered by the web application framework? Well, for the most part, I'd say yes, it is a good idea to use things like the url tag, if you're building a Django template. Stick with the infrastructure provided for building URLs and you'll never worry about whether the correct URL is passed to the user interface. Just reference the URL blueprint by name and let the URL instance take care of the rest.
User interfaces in web applications follow patterns. That is a given. From one page to the next, controls repeat themselves. Things like pagination come to mind. Any given page with a list of objects on it uses pagination controls as a means to avoid dumping every object on a single page — making it impossible for the user to navigate in a cogent manor. The common items, or, generic items rather, are the list and the paginator. The list of objects and how they're rendered can be generalized inside the Django template. As can the pagination controls. These controls move back and forth through a set of objects — usually by appending constraints on the URL.
So how does this paginator change from one set of objects to the next? How does it distinguish between one type of object list and the next? Well, the reality is that it doesn't change much for different object types, or, at all. Forward in motion and backward in motion. Generic behavior that doesn't necessarily warrant using the URL resolution system. Any Javascript code that runs on the page already knows about the current URL — just look it up in the window object. We know how to move forward and backward through a list — just update the current URL. For instance, the browser URL is simply updated from /objects/page1 to /objects/page2. There isn't a need to invoke the URL construction code for this — let the client take care of generic things like this where it makes sense while saving server CPU cycles for more important things.
Showing posts with label generic. Show all posts
Showing posts with label generic. Show all posts
Thursday, November 17, 2011
Friday, November 4, 2011
Dealing With Permissions In Generic Views
Generic views in Django cover a vast range of usage scenarios. That's why they're called generic views — because they implement the abstract patterns common to most applications that are using views. This a huge savings on code-writing cost because there isn't as much of it to write — or maintain thereafter. So, this all well and good, but what about the pre-generic days of writing Django views? Is there nothing of value there we can carry forward and exploit in our newly-fashioned generic views?
Of course, before we used class based views, there were still some degree of generic capabilities that could be attached to our view behavior. They came in the form of decorators. Decorators in Python are a realization of the decorator pattern — we're attaching additional responsibilities to the function. Or, in this case, our view function. But things aren't so straight forward in the brave new generic world of writing views that use classes. How can we deal with things like permissions in our generic views while still honoring the DRY principle?
The decorated permission approach
The authentication system that ships with Django includes the ability to only expose certain views to specific users. If we're writing views as functions, the authentication framework has decorators we can use to ensure the current user has the appropriate permissions. Like this...
This is an elegant approach to ensuring that only authorized user have access to my_view. Since the permission_required decorator is provided by the authentication framework, it's available for every view in our application. And, we only need to implement one line of code where we need to handle permissions. One per view.
The trouble with permission_required in modern Django applications is that they don't fit in nicely with the newer class-based generic view methodology. So how then, can we exploit the power of the generic views in Django while keeping the simplicity of the decorated permission handling?
The inherited permission approach
One thing that class-based views offer that decorators don't is the ability to define defaults that the rest of the view hierarchy in our application can inherit. These defaults include both data attributes and behavior. This is one approach we can use with our class based views to simplify permission handling...
With this approach, able to control permission-based access based on the HTTP method — all within a dictionary overridden by descendant classes. Here is how it works.
First, we're re-creating the base TemplateView class — called MyAppTemplateView. Any other template views used in my application are now going to inherit from this class instead of the standard TemplateView defined by Django. This is how we decorate each view with the added responsibility of ensuring access control.
The dispatch() method is the first call to action for any generic view. So it is here that we want to approve of any additional execution. What were doing here is really simple. We're checking if the user has the permissions defined by the perms attribute. And this is all we need to override. By default, this attribute is an empty dictionary — so no permissions will be validated.
The MyAppNews view simply overrides the perms attribute to ensure the requesting user has the myapp.can_see_news permission. It's not exactly a decorator, but we're retaining some flexibility while staying true to the DRY principle.
Of course, before we used class based views, there were still some degree of generic capabilities that could be attached to our view behavior. They came in the form of decorators. Decorators in Python are a realization of the decorator pattern — we're attaching additional responsibilities to the function. Or, in this case, our view function. But things aren't so straight forward in the brave new generic world of writing views that use classes. How can we deal with things like permissions in our generic views while still honoring the DRY principle?
The decorated permission approach
The authentication system that ships with Django includes the ability to only expose certain views to specific users. If we're writing views as functions, the authentication framework has decorators we can use to ensure the current user has the appropriate permissions. Like this...
from django.shortcuts import render_to_response
from django.contrib.auth.decorators import permission_required
@permission_required('my_app.can_do_stuff')
def my_view(request):
return render_to_response('my_template.html', dict())
This is an elegant approach to ensuring that only authorized user have access to my_view. Since the permission_required decorator is provided by the authentication framework, it's available for every view in our application. And, we only need to implement one line of code where we need to handle permissions. One per view.
The trouble with permission_required in modern Django applications is that they don't fit in nicely with the newer class-based generic view methodology. So how then, can we exploit the power of the generic views in Django while keeping the simplicity of the decorated permission handling?
The inherited permission approach
One thing that class-based views offer that decorators don't is the ability to define defaults that the rest of the view hierarchy in our application can inherit. These defaults include both data attributes and behavior. This is one approach we can use with our class based views to simplify permission handling...
from django.views.generic import TemplateView
from django.http import HttpResponseForbidden
class MyAppTemplateView(TemplateView):
perms = dict()
def dispatch(self, request, *args, **kwargs):
perms = self.perms.get(request.method.lower(), None)
if perms and not request.user.has_perms(perms):
return HttpResponseForbidden()
parent = super(MyAppTemplateView, self)
return parent.dispatch(request, *args, **kwargs)
class MyAppNews(MyAppTemplateView):
template_name = 'news.html'
perms = dict(
get = ('myapp.can_see_news',)
)
With this approach, able to control permission-based access based on the HTTP method — all within a dictionary overridden by descendant classes. Here is how it works.
First, we're re-creating the base TemplateView class — called MyAppTemplateView. Any other template views used in my application are now going to inherit from this class instead of the standard TemplateView defined by Django. This is how we decorate each view with the added responsibility of ensuring access control.
The dispatch() method is the first call to action for any generic view. So it is here that we want to approve of any additional execution. What were doing here is really simple. We're checking if the user has the permissions defined by the perms attribute. And this is all we need to override. By default, this attribute is an empty dictionary — so no permissions will be validated.
The MyAppNews view simply overrides the perms attribute to ensure the requesting user has the myapp.can_see_news permission. It's not exactly a decorator, but we're retaining some flexibility while staying true to the DRY principle.
Friday, July 8, 2011
Django Class-Based Views: A Design Perspective
The release of Django 1.3 introduced the concept of class-based generic views. Prior to 1.3, generic views were written as functions. What's the big fuss over class-based views? What can they possibly offer that functional views can't? Convenience, less code, and elegant design - a property that extends down through Django's core. From a design perspective, class-based views in Django are a better way to implement common view patters with marginal effort than generic function views. For me, having only used class-based views for a few months, I'm very impressed. When I compare generic functions with generic classes, I'm amazed at the difference in quality. This is one of those small enhancements that I think will change Python web development for the better.
Maybe a little history first, shall we? First of all, what makes Django views so useful and easy to work with in the first place? We can tell Django how to map HTTP requests to our view functions using URL configurations. This is useful because we have URL definitions separate from the functions themselves - multiple URL patterns can be handled by a single view function. The URL path segments and query parameters are passed to the function as positional arguments and keyword arguments respectfully.
Having a Python function handle each HTTP request sent to the application is intuitive, no two ways about it. The job of the view function is to take the client's request, perform some business logic, and return a rendering context for the template. For common scenarios, generic view functions can be passed to the URL configuration. For example, listing specific objects or for a detailed view of a single object. For this, generic view functions are perfect. We don't need to write repetitive code that differs only slightly from view to view.
However, we can't use generic views for everything and this is where the Django developer needs to step in and write some custom stuff. Stuff that'll refine a query or pass additional context to the template.
Prior to Django 1.3, where generic class views were introduced, generic functions were customized by passing an info dictionary to the URL configuration. This isn't an ideal coupling since the view now depends on additional data being passed to the URL definition. For instance, if I have a URL where I want to return a list of objects, I can use a generic view that does just that. However, to customize the query, I need to pass additional information to the URL definition that tells the view how to alter the query. So if I wanted to reuse this same view, with the same query modifications, I'd have to duplicate the additional generic view info. Not that this is painfully tedious, just error-prone.
Class-based generic views aims to solve the trouble of binding view-specific data to the URL, and to that end, I think they've succeeded hugely. The new class-based approach introduces the concept of inheritance. This method of extending views is less susceptible to problems with configuring URLs which depend on additional information. Plus, extending generic views is simply elegant from a design perspective.
For example, we can extend the ListView class provided by Django to render a list of objects from our model. At the most basic level, all we really need to tell ListView about is the model to select from. Say we have a Book class. We can define ourselves a new BookList class view for returning lists for books. We're overriding the default model value of ListView.
I find this superior to the decorated customization approach. With decorators, we're wrapping the view function with additional logic. For instance, depending on the request context, HTTP headers, GET values, the URL, and so forth, we'll execute the logic of the generic view differently. Nothing is wrong with this except for the fact that it doesn't sit well with doing things generically for a database view. If I'm writing a list or detail view for things stored in the database, I want as little customization as possible if I'm using generic views. This is a key point - the views are generic because you're supposed to give them only as little information as possible. Just the bare minimum required to produce the appropriate template context.
With the new class-based approach, it's easier to leave the defaults alone, only overriding what's necessary. The model name, for instance. Or if you need more control over the resulting query set, overriding the get_queryset() method. It's best to leave the common stuff to the generic view framework. This is it's selling point, after all. Things like automatically finding the template based on the model name. If you absolutely must change something about a view, there is an attribute or a method you can override. If you find that you're extending the Django generic views and they're becoming large, chances are you shouldn't be using them. That is, if a method you've overridden on a Django generic class view looks nothing like a basic customization, you should think hard about why you're using a generic view in the first place. Maybe you're better off writing a regular, non-generic view. There is nothing wrong with this approach - that's why standard, function-based views exist - for writing business logic.
So from a design perspective, what do class-based generic views bring to the table? A cleaner, more elegant mechanism for displaying database data. In addition to decoupling the customizations that go along with generic views from the URL configurations, class-based generic views embrace inheritance as a means to use default behaviour and override only when necessary. Often the generic behaviour is enough, just tell the view about the basic necessities, and you're off to the races. Django offers a plentiful selection of built-in class-based views to choose from, each of which can be extended cleanly.
Maybe a little history first, shall we? First of all, what makes Django views so useful and easy to work with in the first place? We can tell Django how to map HTTP requests to our view functions using URL configurations. This is useful because we have URL definitions separate from the functions themselves - multiple URL patterns can be handled by a single view function. The URL path segments and query parameters are passed to the function as positional arguments and keyword arguments respectfully.
Having a Python function handle each HTTP request sent to the application is intuitive, no two ways about it. The job of the view function is to take the client's request, perform some business logic, and return a rendering context for the template. For common scenarios, generic view functions can be passed to the URL configuration. For example, listing specific objects or for a detailed view of a single object. For this, generic view functions are perfect. We don't need to write repetitive code that differs only slightly from view to view.
However, we can't use generic views for everything and this is where the Django developer needs to step in and write some custom stuff. Stuff that'll refine a query or pass additional context to the template.
Prior to Django 1.3, where generic class views were introduced, generic functions were customized by passing an info dictionary to the URL configuration. This isn't an ideal coupling since the view now depends on additional data being passed to the URL definition. For instance, if I have a URL where I want to return a list of objects, I can use a generic view that does just that. However, to customize the query, I need to pass additional information to the URL definition that tells the view how to alter the query. So if I wanted to reuse this same view, with the same query modifications, I'd have to duplicate the additional generic view info. Not that this is painfully tedious, just error-prone.
Class-based generic views aims to solve the trouble of binding view-specific data to the URL, and to that end, I think they've succeeded hugely. The new class-based approach introduces the concept of inheritance. This method of extending views is less susceptible to problems with configuring URLs which depend on additional information. Plus, extending generic views is simply elegant from a design perspective.
For example, we can extend the ListView class provided by Django to render a list of objects from our model. At the most basic level, all we really need to tell ListView about is the model to select from. Say we have a Book class. We can define ourselves a new BookList class view for returning lists for books. We're overriding the default model value of ListView.
I find this superior to the decorated customization approach. With decorators, we're wrapping the view function with additional logic. For instance, depending on the request context, HTTP headers, GET values, the URL, and so forth, we'll execute the logic of the generic view differently. Nothing is wrong with this except for the fact that it doesn't sit well with doing things generically for a database view. If I'm writing a list or detail view for things stored in the database, I want as little customization as possible if I'm using generic views. This is a key point - the views are generic because you're supposed to give them only as little information as possible. Just the bare minimum required to produce the appropriate template context.
With the new class-based approach, it's easier to leave the defaults alone, only overriding what's necessary. The model name, for instance. Or if you need more control over the resulting query set, overriding the get_queryset() method. It's best to leave the common stuff to the generic view framework. This is it's selling point, after all. Things like automatically finding the template based on the model name. If you absolutely must change something about a view, there is an attribute or a method you can override. If you find that you're extending the Django generic views and they're becoming large, chances are you shouldn't be using them. That is, if a method you've overridden on a Django generic class view looks nothing like a basic customization, you should think hard about why you're using a generic view in the first place. Maybe you're better off writing a regular, non-generic view. There is nothing wrong with this approach - that's why standard, function-based views exist - for writing business logic.
So from a design perspective, what do class-based generic views bring to the table? A cleaner, more elegant mechanism for displaying database data. In addition to decoupling the customizations that go along with generic views from the URL configurations, class-based generic views embrace inheritance as a means to use default behaviour and override only when necessary. Often the generic behaviour is enough, just tell the view about the basic necessities, and you're off to the races. Django offers a plentiful selection of built-in class-based views to choose from, each of which can be extended cleanly.
Subscribe to:
Posts
(
Atom
)