|
|
@ -1,20 +1,21 @@ |
|
|
|
from collections import OrderedDict |
|
|
|
import django_filters |
|
|
|
import importlib |
|
|
|
import inspect |
|
|
|
import logging |
|
|
|
import re |
|
|
|
|
|
|
|
from django.apps.config import AppConfig |
|
|
|
from django.apps.registry import apps |
|
|
|
from django.conf import settings |
|
|
|
from django.contrib.postgres.fields.jsonb import JSONField |
|
|
|
from django.db.models.base import ModelBase |
|
|
|
from django.db.models.fields import TextField, CharField |
|
|
|
from django.db.models.fields.files import FileField |
|
|
|
from django.db.models.fields.related import ManyToManyField |
|
|
|
from django.template.defaultfilters import capfirst |
|
|
|
from django.utils.translation import ugettext_lazy as _ |
|
|
|
import django_filters |
|
|
|
from django.urls.conf import path |
|
|
|
from django_filters.constants import ALL_FIELDS, EMPTY_VALUES |
|
|
|
from django_filters.fields import ModelMultipleChoiceField |
|
|
|
from django_filters.filters import CharFilter |
|
|
|
from django_filters.filterset import FilterSet |
|
|
|
from django_filters.rest_framework.backends import DjangoFilterBackend |
|
|
@ -23,6 +24,7 @@ from rest_framework import serializers as rest_serializers |
|
|
|
from rest_framework.response import Response |
|
|
|
from rest_framework.routers import DefaultRouter |
|
|
|
from rest_framework.viewsets import ModelViewSet |
|
|
|
from rest_framework.urlpatterns import format_suffix_patterns |
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
@ -65,6 +67,21 @@ class SplitStringCharFilter(django_filters.CharFilter): |
|
|
|
return qs |
|
|
|
|
|
|
|
|
|
|
|
class M2MFilter(django_filters.ModelMultipleChoiceFilter): |
|
|
|
|
|
|
|
class M2MFieldFormField(ModelMultipleChoiceField): |
|
|
|
def clean(self, value): |
|
|
|
if value in EMPTY_VALUES: |
|
|
|
return super().clean(value) |
|
|
|
values = list(map(lambda x: x.replace(' ', '').split(','), value)) |
|
|
|
values = [v for subvalues in values for v in subvalues] |
|
|
|
cleaned_values = tuple(super().clean(values)) |
|
|
|
return (cleaned_values,) if cleaned_values else cleaned_values |
|
|
|
|
|
|
|
field_class = M2MFieldFormField |
|
|
|
distinct = True |
|
|
|
|
|
|
|
|
|
|
|
class ApiFilterSetMixin(FilterSet): |
|
|
|
|
|
|
|
o = CharFilter(method='filter_o') |
|
|
@ -117,7 +134,7 @@ class ApiFilterSetMixin(FilterSet): |
|
|
|
f = model._meta.get_field(f_str) |
|
|
|
|
|
|
|
if f.many_to_many: |
|
|
|
fields[f_str] = ['exact'] |
|
|
|
fields[f_str] = ['exact', 'in', ] |
|
|
|
continue |
|
|
|
|
|
|
|
fields[f_str] = ['exact'] |
|
|
@ -173,6 +190,14 @@ class ApiFilterSetMixin(FilterSet): |
|
|
|
return filter_class(**default) |
|
|
|
return None |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def filter_for_lookup(cls, field, lookup_type): |
|
|
|
f, p = super().filter_for_lookup(field, lookup_type) |
|
|
|
|
|
|
|
if lookup_type == 'in' and isinstance(field, ManyToManyField): |
|
|
|
return M2MFilter, p |
|
|
|
return f, p |
|
|
|
|
|
|
|
|
|
|
|
class BusinessRulesNotImplementedMixin: |
|
|
|
http_method_names = ['get', 'head', 'options', 'trace'] |
|
|
@ -187,6 +212,26 @@ class BusinessRulesNotImplementedMixin: |
|
|
|
raise Exception(_("DELETE Delete não implementado")) |
|
|
|
|
|
|
|
|
|
|
|
class DrfautoapiRouter(DefaultRouter): |
|
|
|
|
|
|
|
def get_urls(self): |
|
|
|
""" |
|
|
|
Generate the list of URL patterns, including a default root view |
|
|
|
for the API, and appending `.json` style format suffixes. |
|
|
|
""" |
|
|
|
urls = super(DefaultRouter, self).get_urls() |
|
|
|
|
|
|
|
if self.include_root_view: |
|
|
|
view = self.get_api_root_view(api_urls = urls) |
|
|
|
root_url = path('', view, name = self.root_view_name) |
|
|
|
urls.append(root_url) |
|
|
|
|
|
|
|
if self.include_format_suffixes: |
|
|
|
urls = format_suffix_patterns(urls, allowed = ['[a-zA-Z.0-9]+']) |
|
|
|
|
|
|
|
return urls |
|
|
|
|
|
|
|
|
|
|
|
class ApiViewSetConstrutor(): |
|
|
|
|
|
|
|
_built_sets = {} |
|
|
@ -208,12 +253,14 @@ class ApiViewSetConstrutor(): |
|
|
|
importlib.import_module(m) |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def router(cls, router_class=DefaultRouter): |
|
|
|
def router(cls, router_class = DrfautoapiRouter): |
|
|
|
router = router_class() |
|
|
|
for app, built_sets in cls._built_sets.items(): |
|
|
|
for model, viewset in built_sets.items(): |
|
|
|
router.register( |
|
|
|
f'{app.label}/{model._meta.model_name}', viewset) |
|
|
|
f'{app.label}/{model._meta.model_name}', |
|
|
|
viewset, |
|
|
|
basename=f'{app.label}_{model._meta.model_name}') |
|
|
|
return router |
|
|
|
|
|
|
|
@classmethod |
|
|
@ -407,3 +454,5 @@ class customize(object): |
|
|
|
ApiViewSetConstrutor._built_sets[ |
|
|
|
self.model._meta.app_config][self.model] = _ApiViewSet |
|
|
|
return _ApiViewSet |
|
|
|
|
|
|
|
|
|
|
|