|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
|
|
from collections import OrderedDict
|
|
|
|
import datetime
|
|
|
|
from itertools import chain
|
|
|
|
|
|
|
|
from django.core.exceptions import PermissionDenied
|
|
|
|
from django.http import Http404
|
|
|
|
from django.utils.encoding import force_text
|
|
|
|
from rest_framework.fields import empty
|
|
|
|
|
|
|
|
from rest_framework.metadata import SimpleMetadata
|
|
|
|
from rest_framework import exceptions, serializers
|
|
|
|
from rest_framework.request import clone_request
|
|
|
|
|
|
|
|
|
|
|
|
class SimpleMetadataWithFilters(SimpleMetadata):
|
|
|
|
"""Override SimpleMetadata, adding info about filters"""
|
|
|
|
|
|
|
|
methods = {"PUT", "POST", "GET", "PATCH"}
|
|
|
|
attrs = [
|
|
|
|
'read_only', 'label', 'help_text',
|
|
|
|
'min_length', 'max_length',
|
|
|
|
'min_value', 'max_value', "write_only",
|
|
|
|
]
|
|
|
|
|
|
|
|
def determine_actions(self, request, view):
|
|
|
|
"""
|
|
|
|
For generic class based views we return information about
|
|
|
|
the fields that are accepted for 'PUT' and 'POST' methods.
|
|
|
|
"""
|
|
|
|
actions = {}
|
|
|
|
for method in self.methods & set(view.allowed_methods):
|
|
|
|
if hasattr(view, 'action_map'):
|
|
|
|
view.action = view.action_map.get(method.lower(), view.action)
|
|
|
|
|
|
|
|
view.request = clone_request(request, method)
|
|
|
|
try:
|
|
|
|
# Test global permissions
|
|
|
|
if hasattr(view, 'check_permissions'):
|
|
|
|
view.check_permissions(view.request)
|
|
|
|
# Test object permissions
|
|
|
|
if method == 'PUT' and hasattr(view, 'get_object'):
|
|
|
|
view.get_object()
|
|
|
|
except (exceptions.APIException, PermissionDenied, Http404):
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
# If user has appropriate permissions for the view, include
|
|
|
|
# appropriate metadata about the fields that should be supplied.
|
|
|
|
serializer = view.get_serializer()
|
|
|
|
actions[method] = self.get_serializer_info(serializer)
|
|
|
|
finally:
|
|
|
|
view.request = request
|
|
|
|
return actions
|
|
|
|
|
|
|
|
def get_field_info(self, field):
|
|
|
|
"""
|
|
|
|
Given an instance of a serializer field, return a dictionary
|
|
|
|
of metadata about it.
|
|
|
|
"""
|
|
|
|
field_info = OrderedDict()
|
|
|
|
field_info['type'] = self.label_lookup[field]
|
|
|
|
field_info['required'] = getattr(field, 'required', False)
|
|
|
|
|
|
|
|
default = getattr(field, 'default', None)
|
|
|
|
if default is not None and default != empty:
|
|
|
|
if isinstance(default, (str, int, bool, datetime.datetime, list)):
|
|
|
|
field_info['default'] = default
|
|
|
|
|
|
|
|
for attr in self.attrs:
|
|
|
|
value = getattr(field, attr, None)
|
|
|
|
if value is not None and value != '':
|
|
|
|
field_info[attr] = force_text(value, strings_only=True)
|
|
|
|
|
|
|
|
if getattr(field, 'child', None):
|
|
|
|
field_info['child'] = self.get_field_info(field.child)
|
|
|
|
elif getattr(field, 'fields', None):
|
|
|
|
field_info['children'] = self.get_serializer_info(field)
|
|
|
|
|
|
|
|
if not isinstance(field, (serializers.RelatedField, serializers.ManyRelatedField)) \
|
|
|
|
and hasattr(field, 'choices'):
|
|
|
|
field_info['choices'] = [
|
|
|
|
{
|
|
|
|
'value': choice_value,
|
|
|
|
'display_name': force_text(choice_name, strings_only=True)
|
|
|
|
}
|
|
|
|
for choice_value, choice_name in field.choices.items()
|
|
|
|
]
|
|
|
|
|
|
|
|
return field_info
|
|
|
|
|
|
|
|
def get_filters_fields(self, request, view):
|
|
|
|
fields = []
|
|
|
|
if hasattr(view, 'get_filter_fields'):
|
|
|
|
fields = view.get_filter_fields(request)
|
|
|
|
elif hasattr(view, 'filter_fields'):
|
|
|
|
fields = view.filter_fields
|
|
|
|
elif hasattr(view, 'filterset_fields'):
|
|
|
|
fields = view.filterset_fields
|
|
|
|
elif hasattr(view, 'get_filterset_fields'):
|
|
|
|
fields = view.get_filterset_fields(request)
|
|
|
|
elif hasattr(view, 'filterset_class'):
|
|
|
|
fields = list(view.filterset_class.Meta.fields) + \
|
|
|
|
list(view.filterset_class.declared_filters.keys())
|
|
|
|
|
|
|
|
if hasattr(view, 'custom_filter_fields'):
|
|
|
|
# 不能写 fields += view.custom_filter_fields
|
|
|
|
# 会改变 view 的 filter_fields
|
|
|
|
fields = list(fields) + list(view.custom_filter_fields)
|
|
|
|
|
|
|
|
if isinstance(fields, dict):
|
|
|
|
fields = list(fields.keys())
|
|
|
|
return fields
|
|
|
|
|
|
|
|
def get_ordering_fields(self, request, view):
|
|
|
|
fields = []
|
|
|
|
if hasattr(view, 'get_ordering_fields'):
|
|
|
|
fields = view.get_ordering_fields(request)
|
|
|
|
elif hasattr(view, 'ordering_fields'):
|
|
|
|
fields = view.ordering_fields
|
|
|
|
return fields
|
|
|
|
|
|
|
|
def determine_metadata(self, request, view):
|
|
|
|
metadata = super(SimpleMetadataWithFilters, self).determine_metadata(request, view)
|
|
|
|
filterset_fields = self.get_filters_fields(request, view)
|
|
|
|
order_fields = self.get_ordering_fields(request, view)
|
|
|
|
|
|
|
|
meta_get = metadata.get("actions", {}).get("GET", {})
|
|
|
|
for k, v in meta_get.items():
|
|
|
|
if k in filterset_fields:
|
|
|
|
v["filter"] = True
|
|
|
|
if k in order_fields:
|
|
|
|
v["order"] = True
|
|
|
|
return metadata
|