Search code examples
pythondjangotastypie

Django Tastypie Override URL with slug


I have the following code:

def override_urls(self):
    return [
        url(r"^(?P<resource_name>%s)/(?P<slug>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
    ]

Which produces an URL like:

/api/v1/nodes/<slug>/

Everything is fine except that self.get_resource_uri(bundle) returns /api/v1/nodes/<id>/ and I cannot compare the current URL with the resource URI effectively.

What am I doing wrong?

Solution: working code

I implemented the proposed solution here: https://github.com/ninuxorg/nodeshot/blob/refactoring/nodeshot/core/base/resources.py

Any additional feedback for improvement is welcome.


Solution

  • You could override get_resource_uri on your resource to return the correct uri. After all, the correct one is the one with the slug since that is the (first) one captured by your resource.

    Update

    The right way to do this is actually to skip override_urls and put this on the Resource's Meta:

    detail_uri_name = 'slug'
    

    TLDR Background

    I dug a bit deeper and it looks like there's a much better place to implement this. The default implementation of get_resource_uri (indirectly) calls self.detail_uri_kwargs and then reverse.

    The default implementation of detail_uri_kwargs in ModelResource just looks up self._meta.detail_uri_name (whose name is not intuitive), and grabs that key off the model. detail_uri_name defaults to pk.

    If you just provide a different name here, you can skip the override_urls and the get_resource_uri!

    Something like this (building on the code linked in comments by the OP):

    from tastypie.resources import ModelResource
    from tastypie.bundle import Bundle
    
    class BaseSlugResource(ModelResource):
        """ Base Model Resource using slug urls """
    
        class Meta:
            abstract = True
            detail_uri_name = 'slug'
    

    I'm not sure off the top of my head whether resource Metas are inherited (I'm going to guess they're not), so this may not work as a base class. Luckily, the one line required is probably fine to paste into each Resource that needs it.