NOTE: this is proof-of-concept code and is no longer maintained.
Rails-like resourceful routing for Django.
This app aims to provide an easy-to-use routing mechanism that calls view methods specific to the type of request being made, loosely following the resource convention found in Ruby on Rails.
Below is an example of the routes supported out of the box, for a Photo model:
Method | URL | {% url %} | Template var name | View | Description |
---|---|---|---|---|---|
GET | /photo | 'photo.index' | index_url | index | display a list of all photos |
GET | /photo/new | 'photo.new' | new_url | new | return an HTML form for creating a new photo |
POST | /photo/new | 'photo.new' | index_url | create | create a new photo |
POST | /photo | 'photo.index' | index_url | create | create a new photo |
GET | /photo/:id | 'photo.show' | show_url | show | display a specific photo |
GET | /photo/:id/edit | 'photo.edit' | edit_url | edit | return an HTML form for editing a photo |
PUT | /photo/:id/edit | 'photo.edit' | edit_url | update | update a specific photo |
PUT | /photo/:id | 'photo.show' | show_url | update | update a specific photo |
DELETE | /photo/:id | 'photo.show' | show_url | destroy | delete a specific photo |
Getting started with the Resourceful app is easy. Just add resources to your
URLconf. Resources are declared by adding URL patterns using the
ResourceView.patterns_for()
helper. To add resources for the Photo
model,
add the following to urls.py
:
[...]
from resourceful.views import ResourceView
from portfolio.models import Photo
urlpatterns = ResourceView.patterns_for(Photo)
Additional resources can be added by appending urlpatterns
:
[...]
from resourceful.views import ResourceView
from blog.models import Entry
urlpatterns += ResourceView.patterns_for(Entry)
Template paths are selected automatically based on the name of the app a model
is in, the name of the model, and the name of the resource requested. For
example, a GET
request for a particular Photo
model item in the portfolio
app at the URL /photo/10
would result in the show()
method to be called and
rendered using the portfolio/photo/show.html
template.
If that template does not exist, a basic default template at
resourceful/show.html
is used instead.
The routing mechanism also detects the format being requested. HTML is,
obviously, the default. When a request is made using AJAX, the format is
automatically changed to JSON based on the X-Requested-With
HTTP header.
The format can also be requested explicitly by making the request with the
_format
query parameter set. Currently only html
and json
are supported.
With no additional code, your application can serve JSON data back to the client.
Similar to selecting a format, specifying the request method is done by setting
the _method
query parameter. For example, the following URL will delete the
photo with ID 10:
/photo/10?_method=delete
Queries can be filtered based on the logged in user by setting the model
manager to ResourceManager
. Simply set it to be the manager for your
model. In your models.py:
from django.db import models
from resourceful.models import ResourceManager
class Photo(models.Model):
[...]
objects = ResourceManager()
Customizing the default behavior can be done by subclassing ResourceView
and
overriding the desired action method. For example, to change the behavior of
the index
action, create your own subclass (in your app's views.py):
from resourceful.views import ResourceView
class MyResourceView(ResourceView):
def index(request, *args, **kwargs):
< your custom code >
In your urls.py
use MyResourceView
instead:
[...]
from blog.models import Entry
from myapp.views import MyResourceView
urlpatterns = MyResourceView.patterns_for(Entry)
With the Resourceful app, views in your application take on a different meaning. Views now represent a specific action taking place within the application. As an example, here is a typical view handling a form submission:
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
The above view handles presenting a form to the user as well as processing a posted data. Higher up, there is no distinction whether the request made was getting data or submitting data. Additionally, there is no distinction between posting new data and updating existing data. Such distinctions are generally left up to the user and are usually handled all within a single view.
Resourceful views change that. The above example becomes:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from resourceful.views import ResourceView
class MyResourceView(ResourceView):
def new(self, request, *args, **kwargs):
form = ContactForm()
return render(request, 'contact.html', {
'form': form,
})
def create(self, request, *args, **kwargs):
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
return render(request, 'contact.html', {
'form': form,
})
Here there is no logic necessary for detecting the request's intent; that has been determined for you in advance.
If using PIP, add the following to requirements.txt
:
-e git://github.com/rca/django-resourceful.git#egg=django-resourceful
It can also be installed on the command line:
pip install -e git://github.com/rca/django-resourceful.git#egg=django-resourceful