Package: django-urlmodel
Creating rich and dry URLs for a Django model.IntroductionDisclaimer.Until release of version 1.0, API could significantly change.As I started using class-based views for Django, I understood what theget_absolute_urlmethod was about. Then I encountered the problem of using URLs that required more than once piece of information from a model instance, let’s say, not a single primary key or slug. That’s a bit abstract, take:/regions/cat-cat-province/towns/mieaou/This identifies Mieaou town within Cat-Cat Province (there’s another Mieaou town within Copy-Cat Province). Now let’s say the usual list of things you’ll do with a model is listing, reading detail, creating, updating, deleting (roughly,CRUD). Roughly, you’ll have this URLs:/regions/cat-cat-province/towns/list/regions/cat-cat-province/towns/create/regions/cat-cat-province/towns/mieaou/edit/regions/cat-cat-province/towns/mieaou/deleteAn important part to notice is that we’re usingmore than one piece of information per instance, which makes things a bit more messy than just a pk. Why not just use a pk? First, Ithinkthere are security implications. Second, nobody wants to remember a pk. Third, programmers respect well-formed URLs and look down to senseless sequences of numbers with unfathomable disdain.What if you provide a link to the edit and delete sections? You’ll probably go for:# urls.py

urlpatterns = patterns('',
    # ...
    url(
        '^regions/(?P<region_slug>[\w-]+)/towns/(?P<town_slug>[\w-]+)/edit/?$',
        name='town-update'
    ),
    # ...
)With something in your template like:# html

<a href="{% url 'town-update' region_slug=town.region.name_slug town_slug=town.name_slug %}">
  Update this town
</a>Note: I mostly use “update” for internal stuff for convention and readability (“update” has the length as “create” and “delete” and “detail” and “search”), but I use “edit” for usability when it’ll be read by the end-user.The latter one is not veryDRY. So I thought I could start writing aget_update_urlmethod, and so on. Then every model class definition would have a set ofget_detail_url,get_update_url,get_delete_urlmethods, plusget_create_urlandget_list_urlmethods (in the original project, it was “search” instead of “list”). Now, given that my URLs have roughly the same naming format for every model (town-list,town-create,town-detail,town-update,town-delete), that is not very DRY either!I decided to write a smart and flexible URL system so that the next time I would need a list-create-detail-update-delete set of URLs, things would be as easy as adding a mixin to the inheritance tree of the model.InstallationI know, my requirements suck:Python 3Django 1.6I’m not sure if this app will not work on previous versions of Django, but I think I will not with Python 2.To install version 0.1:pip install django-urlmodelTo install the latest version, run the command:pip install git+git://github.com/jleeothon/urlmodel.gitHow to useUsing the default CRUD urls is as easy as extending funcionality as a mixin:# models.py

from django.db import models

class Town(CrudUrlModelMixin, models.Model):
    pass

# or, if you're only going to extend the urlmodel functionality...

class Town(CrudUrlModel):
    passThe former example will create a set of five methods (class-level: list, create; instance-level: detail, update, delete) that expect an URL based on the model name and the name of the “action”. Also, these expect an URL keyword argument called “pk”.In order to use a slug field, you should overrideslug_kwarg_nameto match the URL kwarg:# urls.py

urlpatterns = patterns('',
    # ...
    url(
        '^digimons/(?P<name>[\w-]+)/?$',
        name='digimon-detail'
    ),
    # ...
)andslug_field_name, to match the model slug:# models.py

class Digimon(UrlModelMixin, models.Model):
    name = CharField(max_length=100)
    sluggified_name = SlugField(max_length=100)

    slug_kwarg_name = 'name'
    slug_field_name = 'sluggified_name'Try out their lazy equivalents,LazyCrudUrlModelMixinandLazyCrudUrlModel!Note.CrudUrlModel provides implementation forget_absolute_urltoo, and defaults toget_detail_url.Advanced stuffIf the default “CRUD” system (here: list, create, detail, update, delete) do not work for you, you can try outUrlModelandUrlModelMixin(plus their lazy counterparts).Action URLsThese are URLs based on “action names”, such as “detail”, “create”, etc. For convention, ease and readability, you should try to stick to these methods, e.g.:class TownPerson(UrlModelMixin, Model):

    def get_defenestrate_url(self):
        # expects townperson-defenestrate to exist.
        return self.get_instance_action_url("defenestrate")

    @classmethod
    def get_last_defenestrated(cls):
        # expects townperson-last-defenestrated to exist.
        return cls.get_class_action_url("last-defenestrated")Extra information for URLIf you need to rely on more information than a single pk or slug, use*argsand**kwargsto pass on this information to theurlresolvers.reversemethod:class Town(CrudUrlModelMixin, Model):

    def get_detail_url(self):
        return super().get_detail_url(region_slug=self.region.sluggified_name)The above example does also work similarly for the simplerUrlModelMixinclass.Be careful!,instance url methods (get_instance_urlandget_instance_action_url) always pass the pk or slug argument tourlresolvers.reverse.Custom URL namesIf you want to provide a custom URL instead of an automaticmodelname-action, use@classmethod get_class_url(cls, url_name, *args, **kwargs)andget_instance_url(self, url_name, *args, **kwargs).Format for action URLsNote:this section is subject to change in upcoming versions.Action URLs are formattedmodelname-actionby default. To change this format, override theaction_url_formatterobject or provide aformat_actionclass method. If you provide the latter (method), the former (object) will be ignored:action_url_formatter = lambda model, action: '%s-%s' % (model, action)
# this signature will override action_url_formatter
# @classmethod
# def format_action(cls, modelname, action):
#     passProposalsProvide support for Python 2, probably throughsix.Submit this project to PyPI.Resourcesurl template tagReversing URLsSlug fieldsClass-based views