6

I'm wondering if there is a clean way to retrieve an object from its URL with django rest framework. Surely there should be, as it seems to be what's happening when using HyperlinkedRelatedField.

For instance, I have this URL /api/comment/26 as a string. From my view, how can I get the comment instance with pk=26?

Of course I could redo the work and work on the string but it must be a better way?

Thanks a lot.

EDIT:

This is how I solved it at the end:

resolve('/api/comment/26/').func.cls.model will return my model Comment. resolve('/api/category/1/').kwargs['pk'] will return the pk.

Which gives you:

from django.core.urlresolvers import resolve

resolved_func, unused_args, resolved_kwargs = resolve('/api/category/1/')
resolved_func.cls.model.objects.get(pk=resolved_kwargs['pk'])
Vincent Alvo
  • 155
  • 1
  • 2
  • 9
  • Remember that if you have a fully qualified URL (e.g. starting with "http...") you need to extract its `path` and pass that to `resolve`. This can be done with the [urlparse](https://docs.python.org/2/library/urlparse.html) module. – Christoffer Jul 06 '15 at 18:52
  • 1
    I didn't look into it to much but for me resolved_func.cls returns the view set so I needed to use the following to get to the model: resolved_func.cls.serializer_class.Meta.model.objects.get(pk=resolved_kwargs['pk']) – Semprini Nov 24 '15 at 01:32
  • This is not working with django 2.1 and python 3.5 anymore – Philipp S. Sep 11 '19 at 16:59

3 Answers3

3

I suspect your best bet would be to manually keep a map of models to url patterns — not too dissimilar from a URLConf.

If that doesn't rock your boat you could pass the path into resolve.

This will give you a ResolverMatch upon which you'll find the func that was returned by the as_view call when you set up your URLs.

The __name__ attribute of your view function will be that of your original view class. Do something like globals()[class_name] to get the class itself.

From there access the model attribute.

I hope that helps. As I say, you might just want to map models to URLs yourself.

Community
  • 1
  • 1
Carlton Gibson
  • 7,278
  • 2
  • 36
  • 46
  • Thanks for your help!!! Nearly there, I tweaked a bit your answer to get exactly want I needed that way: `resolve('/api/category/1/').func.cls.model` – Vincent Alvo Mar 17 '14 at 15:12
  • Ah, `...func.cls` is there is it? — Never needed it but that's much cleaner. Thank you to you too! – Carlton Gibson Mar 17 '14 at 20:22
2

With class-based views, something like the following seems needed:

resolve(url).func.cls.serializer_class.Meta.model.objects.get(
    **resolve(url).kwargs)
piro
  • 13,378
  • 5
  • 34
  • 38
0

Solution above did not work for me, the following did work though:

from django.core.urlresolvers import resolve

resolved_func, unused_args, resolved_kwargs = resolve('/api/category/1/')
resolved_func.cls().get_queryset().get(id=resolved_kwargs['pk'])

additionally this solution uses the built in queryset of your view, which might have annotations or important filters.

Using HyperlinkedModelSerializer I actually needed to do this with a full url. For this to work, you need to extract the path first, resulting in:

import urllib.parse
from django.core.urlresolvers import resolve

def obj_from_url(url):
    path = urllib.parse.urlparse(url).path
    resolved_func, unused_args, resolved_kwargs = resolve(path)
    return resolved_func.cls().get_queryset().get(id=resolved_kwargs['pk'])
Pinna_be
  • 4,517
  • 2
  • 18
  • 34
  • `django.core.urlresolvers` module has been removed in Django 2.0 and url-related functions (like `resolve`) has been moved to `django.urls`: https://docs.djangoproject.com/en/3.0/ref/urlresolvers/#resolve – EMiDU Feb 02 '20 at 18:59