mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-11-26 18:37:12 +00:00
Improve REST API with filters
This commit is contained in:
parent
bc97eb1eb4
commit
417cd5da04
@ -1,7 +1,8 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
from rest_framework.filters import SearchFilter
|
||||||
|
|
||||||
from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer
|
from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer
|
||||||
from ..models import ActivityType, Activity, Guest
|
from ..models import ActivityType, Activity, Guest
|
||||||
@ -15,6 +16,8 @@ class ActivityTypeViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = ActivityType.objects.all()
|
queryset = ActivityType.objects.all()
|
||||||
serializer_class = ActivityTypeSerializer
|
serializer_class = ActivityTypeSerializer
|
||||||
|
filter_backends = [DjangoFilterBackend]
|
||||||
|
filterset_fields = ['name', 'can_invite', ]
|
||||||
|
|
||||||
|
|
||||||
class ActivityViewSet(viewsets.ModelViewSet):
|
class ActivityViewSet(viewsets.ModelViewSet):
|
||||||
@ -25,6 +28,8 @@ class ActivityViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Activity.objects.all()
|
queryset = Activity.objects.all()
|
||||||
serializer_class = ActivitySerializer
|
serializer_class = ActivitySerializer
|
||||||
|
filter_backends = [DjangoFilterBackend]
|
||||||
|
filterset_fields = ['name', 'description', 'activity_type', ]
|
||||||
|
|
||||||
|
|
||||||
class GuestViewSet(viewsets.ModelViewSet):
|
class GuestViewSet(viewsets.ModelViewSet):
|
||||||
@ -35,3 +40,5 @@ class GuestViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Guest.objects.all()
|
queryset = Guest.objects.all()
|
||||||
serializer_class = GuestSerializer
|
serializer_class = GuestSerializer
|
||||||
|
filter_backends = [SearchFilter]
|
||||||
|
search_fields = ['$name', ]
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import routers, serializers, viewsets
|
from rest_framework import routers, serializers, viewsets
|
||||||
|
from rest_framework.filters import SearchFilter
|
||||||
from activity.api.urls import register_activity_urls
|
from activity.api.urls import register_activity_urls
|
||||||
from member.api.urls import register_members_urls
|
from member.api.urls import register_members_urls
|
||||||
from note.api.urls import register_note_urls
|
from note.api.urls import register_note_urls
|
||||||
@ -33,6 +35,9 @@ class UserViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
filter_backends = [DjangoFilterBackend, SearchFilter]
|
||||||
|
filterset_fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ]
|
||||||
|
search_fields = ['$username', '$first_name', '$last_name', ]
|
||||||
|
|
||||||
|
|
||||||
# Routers provide an easy way of automatically determining the URL conf.
|
# Routers provide an easy way of automatically determining the URL conf.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
|
||||||
from .serializers import ChangelogSerializer
|
from .serializers import ChangelogSerializer
|
||||||
@ -15,3 +16,5 @@ class ChangelogViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Changelog.objects.all()
|
queryset = Changelog.objects.all()
|
||||||
serializer_class = ChangelogSerializer
|
serializer_class = ChangelogSerializer
|
||||||
|
filter_backends = [DjangoFilterBackend]
|
||||||
|
filterset_fields = ['model', 'action', "instance_pk", 'user', 'ip',]
|
||||||
|
@ -81,7 +81,7 @@ def save_object(sender, instance, **kwargs):
|
|||||||
model = instance.__class__
|
model = instance.__class__
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
previous_json = JSONRenderer().render(CustomSerializer(previous).data).decode("UTF-8")
|
previous_json = JSONRenderer().render(CustomSerializer(previous).data).decode("UTF-8") if previous else None
|
||||||
instance_json = JSONRenderer().render(CustomSerializer(instance).data).decode("UTF-8")
|
instance_json = JSONRenderer().render(CustomSerializer(instance).data).decode("UTF-8")
|
||||||
|
|
||||||
if previous_json == instance_json:
|
if previous_json == instance_json:
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
app_name = 'logs'
|
|
||||||
|
|
||||||
# TODO User interface
|
|
||||||
urlpatterns = [
|
|
||||||
]
|
|
@ -2,6 +2,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
from rest_framework.filters import SearchFilter
|
||||||
|
|
||||||
from .serializers import ProfileSerializer, ClubSerializer, RoleSerializer, MembershipSerializer
|
from .serializers import ProfileSerializer, ClubSerializer, RoleSerializer, MembershipSerializer
|
||||||
from ..models import Profile, Club, Role, Membership
|
from ..models import Profile, Club, Role, Membership
|
||||||
@ -25,6 +26,8 @@ class ClubViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Club.objects.all()
|
queryset = Club.objects.all()
|
||||||
serializer_class = ClubSerializer
|
serializer_class = ClubSerializer
|
||||||
|
filter_backends = [SearchFilter]
|
||||||
|
search_fields = ['$name', ]
|
||||||
|
|
||||||
|
|
||||||
class RoleViewSet(viewsets.ModelViewSet):
|
class RoleViewSet(viewsets.ModelViewSet):
|
||||||
@ -35,6 +38,8 @@ class RoleViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.all()
|
||||||
serializer_class = RoleSerializer
|
serializer_class = RoleSerializer
|
||||||
|
filter_backends = [SearchFilter]
|
||||||
|
search_fields = ['$name', ]
|
||||||
|
|
||||||
|
|
||||||
class MembershipViewSet(viewsets.ModelViewSet):
|
class MembershipViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -5,7 +5,8 @@ from rest_framework import serializers
|
|||||||
from rest_polymorphic.serializers import PolymorphicSerializer
|
from rest_polymorphic.serializers import PolymorphicSerializer
|
||||||
|
|
||||||
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
|
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
|
||||||
from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory
|
from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \
|
||||||
|
TemplateTransaction
|
||||||
|
|
||||||
|
|
||||||
class NoteSerializer(serializers.ModelSerializer):
|
class NoteSerializer(serializers.ModelSerializer):
|
||||||
@ -111,6 +112,17 @@ class TransactionSerializer(serializers.ModelSerializer):
|
|||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateTransactionSerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
REST API Serializer for Transactions.
|
||||||
|
The djangorestframework plugin will analyse the model `TemplateTransaction` and parse all fields in the API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TemplateTransaction
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class MembershipTransactionSerializer(serializers.ModelSerializer):
|
class MembershipTransactionSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
REST API Serializer for Membership transactions.
|
REST API Serializer for Membership transactions.
|
||||||
@ -120,3 +132,11 @@ class MembershipTransactionSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = MembershipTransaction
|
model = MembershipTransaction
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionPolymorphicSerializer(PolymorphicSerializer):
|
||||||
|
model_serializer_mapping = {
|
||||||
|
Transaction: TransactionSerializer,
|
||||||
|
TemplateTransaction: TemplateTransactionSerializer,
|
||||||
|
MembershipTransaction: MembershipTransactionSerializer,
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from .views import NotePolymorphicViewSet, AliasViewSet, \
|
from .views import NotePolymorphicViewSet, AliasViewSet, \
|
||||||
TemplateCategoryViewSet, TransactionViewSet, TransactionTemplateViewSet, MembershipTransactionViewSet
|
TemplateCategoryViewSet, TransactionViewSet, TransactionTemplateViewSet
|
||||||
|
|
||||||
|
|
||||||
def register_note_urls(router, path):
|
def register_note_urls(router, path):
|
||||||
@ -15,4 +15,3 @@ def register_note_urls(router, path):
|
|||||||
router.register(path + '/transaction/category', TemplateCategoryViewSet)
|
router.register(path + '/transaction/category', TemplateCategoryViewSet)
|
||||||
router.register(path + '/transaction/transaction', TransactionViewSet)
|
router.register(path + '/transaction/transaction', TransactionViewSet)
|
||||||
router.register(path + '/transaction/template', TransactionTemplateViewSet)
|
router.register(path + '/transaction/template', TransactionTemplateViewSet)
|
||||||
router.register(path + '/transaction/membership', MembershipTransactionViewSet)
|
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
|
from rest_framework.filters import SearchFilter
|
||||||
|
|
||||||
from .serializers import NoteSerializer, NotePolymorphicSerializer, NoteClubSerializer, NoteSpecialSerializer, \
|
from .serializers import NoteSerializer, NotePolymorphicSerializer, NoteClubSerializer, NoteSpecialSerializer, \
|
||||||
NoteUserSerializer, AliasSerializer, \
|
NoteUserSerializer, AliasSerializer, \
|
||||||
TemplateCategorySerializer, TransactionTemplateSerializer, TransactionSerializer, MembershipTransactionSerializer
|
TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer
|
||||||
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
|
from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
|
||||||
from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory
|
from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory
|
||||||
|
|
||||||
|
|
||||||
class NoteViewSet(viewsets.ModelViewSet):
|
class NoteViewSet(viewsets.ModelViewSet):
|
||||||
@ -139,6 +141,8 @@ class TemplateCategoryViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = TemplateCategory.objects.all()
|
queryset = TemplateCategory.objects.all()
|
||||||
serializer_class = TemplateCategorySerializer
|
serializer_class = TemplateCategorySerializer
|
||||||
|
filter_backends = [SearchFilter]
|
||||||
|
search_fields = ['$name', ]
|
||||||
|
|
||||||
|
|
||||||
class TransactionTemplateViewSet(viewsets.ModelViewSet):
|
class TransactionTemplateViewSet(viewsets.ModelViewSet):
|
||||||
@ -149,6 +153,8 @@ class TransactionTemplateViewSet(viewsets.ModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = TransactionTemplate.objects.all()
|
queryset = TransactionTemplate.objects.all()
|
||||||
serializer_class = TransactionTemplateSerializer
|
serializer_class = TransactionTemplateSerializer
|
||||||
|
filter_backends = [DjangoFilterBackend]
|
||||||
|
filterset_fields = ['name', 'amount', 'display', 'category', ]
|
||||||
|
|
||||||
|
|
||||||
class TransactionViewSet(viewsets.ModelViewSet):
|
class TransactionViewSet(viewsets.ModelViewSet):
|
||||||
@ -158,14 +164,6 @@ class TransactionViewSet(viewsets.ModelViewSet):
|
|||||||
then render it on /api/note/transaction/transaction/
|
then render it on /api/note/transaction/transaction/
|
||||||
"""
|
"""
|
||||||
queryset = Transaction.objects.all()
|
queryset = Transaction.objects.all()
|
||||||
serializer_class = TransactionSerializer
|
serializer_class = TransactionPolymorphicSerializer
|
||||||
|
filter_backends = [SearchFilter]
|
||||||
|
search_fields = ['$reason', ]
|
||||||
class MembershipTransactionViewSet(viewsets.ModelViewSet):
|
|
||||||
"""
|
|
||||||
REST API View set.
|
|
||||||
The djangorestframework plugin will get all `MembershipTransaction` objects, serialize it to JSON with the given serializer,
|
|
||||||
then render it on /api/note/transaction/membership/
|
|
||||||
"""
|
|
||||||
queryset = MembershipTransaction.objects.all()
|
|
||||||
serializer_class = MembershipTransactionSerializer
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"model": "note.note",
|
"model": "note.note",
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
"fields": {
|
"fields": {
|
||||||
"polymorphic_ctype": 37,
|
"polymorphic_ctype": 40,
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"display_image": "",
|
"display_image": "",
|
||||||
@ -14,7 +14,7 @@
|
|||||||
"model": "note.note",
|
"model": "note.note",
|
||||||
"pk": 2,
|
"pk": 2,
|
||||||
"fields": {
|
"fields": {
|
||||||
"polymorphic_ctype": 37,
|
"polymorphic_ctype": 40,
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"display_image": "",
|
"display_image": "",
|
||||||
@ -25,7 +25,7 @@
|
|||||||
"model": "note.note",
|
"model": "note.note",
|
||||||
"pk": 3,
|
"pk": 3,
|
||||||
"fields": {
|
"fields": {
|
||||||
"polymorphic_ctype": 37,
|
"polymorphic_ctype": 40,
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"display_image": "",
|
"display_image": "",
|
||||||
@ -36,7 +36,7 @@
|
|||||||
"model": "note.note",
|
"model": "note.note",
|
||||||
"pk": 4,
|
"pk": 4,
|
||||||
"fields": {
|
"fields": {
|
||||||
"polymorphic_ctype": 37,
|
"polymorphic_ctype": 40,
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"display_image": "",
|
"display_image": "",
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"model": "note.note",
|
"model": "note.note",
|
||||||
"pk": 5,
|
"pk": 5,
|
||||||
"fields": {
|
"fields": {
|
||||||
"polymorphic_ctype": 36,
|
"polymorphic_ctype": 39,
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"display_image": "",
|
"display_image": "",
|
||||||
@ -58,7 +58,7 @@
|
|||||||
"model": "note.note",
|
"model": "note.note",
|
||||||
"pk": 6,
|
"pk": 6,
|
||||||
"fields": {
|
"fields": {
|
||||||
"polymorphic_ctype": 36,
|
"polymorphic_ctype": 39,
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"display_image": "",
|
"display_image": "",
|
||||||
|
@ -137,12 +137,14 @@ REST_FRAMEWORK = {
|
|||||||
# or allow read-only access for unauthenticated users.
|
# or allow read-only access for unauthenticated users.
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
# TODO Maybe replace it with our custom permissions system
|
# TODO Maybe replace it with our custom permissions system
|
||||||
'rest_framework.permissions.DjangoModelPermissions'
|
'rest_framework.permissions.DjangoModelPermissions',
|
||||||
],
|
],
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||||
'rest_framework.authentication.SessionAuthentication',
|
'rest_framework.authentication.SessionAuthentication',
|
||||||
'rest_framework.authentication.TokenAuthentication',
|
'rest_framework.authentication.TokenAuthentication',
|
||||||
]
|
],
|
||||||
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||||
|
'PAGE_SIZE': 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
|
@ -20,8 +20,7 @@ urlpatterns = [
|
|||||||
path('accounts/', include('django.contrib.auth.urls')),
|
path('accounts/', include('django.contrib.auth.urls')),
|
||||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('logs/', include('logs.urls')),
|
path('api/', include('api.urls')),
|
||||||
path('api/', include('api.urls')),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
5
templates/django_filters/rest_framework/crispy_form.html
Normal file
5
templates/django_filters/rest_framework/crispy_form.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{% load crispy_forms_tags %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<h2>{% trans "Field filters" %}</h2>
|
||||||
|
{% crispy filter.form %}
|
6
templates/django_filters/rest_framework/form.html
Normal file
6
templates/django_filters/rest_framework/form.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<h2>{% trans "Field filters" %}</h2>
|
||||||
|
<form class="form" action="" method="get">
|
||||||
|
{{ filter.form.as_p }}
|
||||||
|
<button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
|
||||||
|
</form>
|
1
templates/django_filters/widgets/multiwidget.html
Normal file
1
templates/django_filters/widgets/multiwidget.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
{% for widget in widget.subwidgets %}{% include widget.template_name %}{% if forloop.first %}-{% endif %}{% endfor %}
|
Loading…
Reference in New Issue
Block a user