|
7 | 7 |
|
8 | 8 | import inflection
|
9 | 9 | from django.db.models import Manager
|
| 10 | +from django.template import loader |
10 | 11 | from django.utils import encoding
|
11 | 12 | from rest_framework import relations, renderers
|
12 | 13 | from rest_framework.fields import SkipField, get_attribute
|
@@ -606,3 +607,53 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
|
606 | 607 | return super(JSONRenderer, self).render(
|
607 | 608 | render_data, accepted_media_type, renderer_context
|
608 | 609 | )
|
| 610 | + |
| 611 | + |
| 612 | +class BrowsableAPIRenderer(renderers.BrowsableAPIRenderer): |
| 613 | + template = 'rest_framework_json_api/api.html' |
| 614 | + includes_template = 'rest_framework_json_api/includes.html' |
| 615 | + |
| 616 | + def get_context(self, data, accepted_media_type, renderer_context): |
| 617 | + context = super(BrowsableAPIRenderer, self).get_context( |
| 618 | + data, accepted_media_type, renderer_context |
| 619 | + ) |
| 620 | + view = renderer_context['view'] |
| 621 | + |
| 622 | + context['includes_form'] = self.get_includes_form(view) |
| 623 | + |
| 624 | + return context |
| 625 | + |
| 626 | + @classmethod |
| 627 | + def _get_included_serializers(cls, serializer, prefix='', already_seen=None): |
| 628 | + if not already_seen: |
| 629 | + already_seen = set() |
| 630 | + |
| 631 | + if serializer in already_seen: |
| 632 | + return [] |
| 633 | + |
| 634 | + included_serializers = [] |
| 635 | + already_seen.add(serializer) |
| 636 | + |
| 637 | + for include, included_serializer in utils.get_included_serializers(serializer).items(): |
| 638 | + included_serializers.append(f'{prefix}{include}') |
| 639 | + included_serializers.extend( |
| 640 | + cls._get_included_serializers( |
| 641 | + included_serializer, f'{prefix}{include}.', |
| 642 | + already_seen=already_seen |
| 643 | + ) |
| 644 | + ) |
| 645 | + |
| 646 | + return included_serializers |
| 647 | + |
| 648 | + def get_includes_form(self, view): |
| 649 | + try: |
| 650 | + serializer_class = view.get_serializer_class() |
| 651 | + except AttributeError: |
| 652 | + return |
| 653 | + |
| 654 | + if not hasattr(serializer_class, 'included_serializers'): |
| 655 | + return |
| 656 | + |
| 657 | + template = loader.get_template(self.includes_template) |
| 658 | + context = {'elements': self._get_included_serializers(serializer_class)} |
| 659 | + return template.render(context) |
0 commit comments