|
| 1 | +from django.core.exceptions import ImproperlyConfigured |
| 2 | +from django.core.urlresolvers import NoReverseMatch |
1 | 3 | from django.db.models import Model, QuerySet |
2 | 4 | from django.db.models.manager import BaseManager |
3 | 5 | from rest_framework import generics |
| 6 | +from rest_framework.relations import Hyperlink |
4 | 7 | from rest_framework.response import Response |
5 | 8 | from rest_framework.exceptions import NotFound, MethodNotAllowed |
| 9 | +from rest_framework.reverse import reverse |
6 | 10 |
|
7 | 11 | from rest_framework_json_api.exceptions import Conflict |
8 | 12 | from rest_framework_json_api.serializers import ResourceIdentifierObjectSerializer |
|
11 | 15 |
|
12 | 16 | class RelationshipView(generics.GenericAPIView): |
13 | 17 | serializer_class = ResourceIdentifierObjectSerializer |
14 | | - self_view_name = None |
15 | | - related_view_name = None |
| 18 | + self_link_view_name = None |
| 19 | + related_link_view_name = None |
16 | 20 |
|
17 | | - def get_self_link(self): |
18 | | - return 'self_link' |
| 21 | + def __init__(self, **kwargs): |
| 22 | + super(RelationshipView, self).__init__(**kwargs) |
| 23 | + # We include this simply for dependency injection in tests. |
| 24 | + # We can't add it as a class attributes or it would expect an |
| 25 | + # implicit `self` argument to be passed. |
| 26 | + self.reverse = reverse |
19 | 27 |
|
20 | | - def get_related_link(self): |
21 | | - return 'related_link' |
| 28 | + |
| 29 | + |
| 30 | + def get_url(self, name, view_name, kwargs, request): |
| 31 | + """ |
| 32 | + Given an object, return the URL that hyperlinks to the object. |
| 33 | +
|
| 34 | + May raise a `NoReverseMatch` if the `view_name` and `lookup_field` |
| 35 | + attributes are not configured to correctly match the URL conf. |
| 36 | + """ |
| 37 | + |
| 38 | + # Return None if the view name is not supplied |
| 39 | + if not view_name: |
| 40 | + return None |
| 41 | + |
| 42 | + # Return the hyperlink, or error if incorrectly configured. |
| 43 | + try: |
| 44 | + url = self.reverse(view_name, kwargs=kwargs, request=request) |
| 45 | + except NoReverseMatch: |
| 46 | + msg = ( |
| 47 | + 'Could not resolve URL for hyperlinked relationship using ' |
| 48 | + 'view name "%s". You may have failed to include the related ' |
| 49 | + 'model in your API, or incorrectly configured the ' |
| 50 | + '`lookup_field` attribute on this field.' |
| 51 | + ) |
| 52 | + raise ImproperlyConfigured(msg % view_name) |
| 53 | + |
| 54 | + if url is None: |
| 55 | + return None |
| 56 | + |
| 57 | + return Hyperlink(url, name) |
22 | 58 |
|
23 | 59 | def get_links(self): |
24 | 60 | return_data = OrderedDict() |
25 | | - self_link = self.get_self_link() |
26 | | - related_link = self.get_related_link() |
| 61 | + self_link = self.get_url('self', self.self_link_view_name, self.kwargs, self.request) |
| 62 | + related_kwargs = {self.lookup_field: self.kwargs.get(self.lookup_field)} |
| 63 | + related_link = self.get_url('related', self.related_link_view_name, related_kwargs, self.request) |
27 | 64 | if self_link: |
28 | 65 | return_data.update({'self': self_link}) |
29 | 66 | if related_link: |
|
0 commit comments