How to expose Django-Constance settings via Django Rest Framework?
Question:
I am building a project in which I need to have a few custom settings that are editable by certain users which do not have access to the django admin panel, who access the application via an Angular frontend.
I installed django-constance in order to have these custom settings editable, as it was the most recommended package I could find on the Django packages site. My problem now is that I do not know how to do to serve the settings on my API rest.
I started with some customized view:
class ConstanceSettingSerializer(serializers.Serializer):
name = serializers.CharField()
value = serializers.Field()
defult_value = serializers.Field()
modified = serializers.BooleanField(read_only=True)
from constance import settings as constance_settings
class ConstanceView(APIView):
def get(self, request):
settings = constance_settings.CONFIG.items()
return Response(settings, status=status.HTTP_200_OK)
But now I dont know how to pass those settings correctly to my serializer. I tried this without success:
settings_serializer = ConstanceSettingSerializer(settings)
return Response(settings_serializer.data, status=status.HTTP_200_OK)
And I am only getting errors.
Some idea how to do this properly?
Thanks!
Answers:
Your serializer needs to know what to return. So for each field, you can do something like this:
class ConstanceSettingSerializer(serializers.Serializer):
setting_name = serializers.SerializerMethodField()
def get_setting_name(self):
settings = constance_settings.CONFIG.items()
# Retrieve your setting's value here and return
return setting_value
That’s on the way out. If you wanted to be able to change settings via PUT/POST/PATCH, you need to override create/update in your serializer and implement the logic to save the values yourself.
Another way could be to check how the storage of the settings is implemented.
I have not used the constance settings so i cant say. But if it uses DB to store the settings, you can implement model serializer for the model which they use.
Give you a demo
from .utils import get_settings
from constance import config
from rest_framework.viewsets import ViewSet
class SettingViewSet(ViewSet):
permission_classes = (IsAuthenticated,)
def setting(self, request, allow_settings):
if request.method == 'GET':
# list all setting items
return Response(data=get_settings(allow_settings))
else:
# change all allow setting items in allow_settings
for key in request.data:
if key in allow_settings and key in getattr(settings, 'CONSTANCE_CONFIG', {}):
value = request.data[key]
setattr(config, key, '' if value is None else value)
return Response(data=get_settings(allow_settings))
def create(self, request):
"""
<p>update with POST:<code>{'Key': new_value}</code>
"""
allow_settings = [key for key, options in getattr(settings, 'CONSTANCE_CONFIG', {}).items()]
return self.setting(request, allow_settings)
def list(self, request):
"""
get all setting item
"""
allow_settings = [key for key, options in getattr(settings, 'CONSTANCE_CONFIG', {}).items()]
return self.setting(request, allow_settings)
in utils.py:
def get_settings(allow_settings):
setting_list = []
for key, options in getattr(settings, 'CONSTANCE_CONFIG', {}).items():
if key in allow_settings:
default, help_text = options[0], options[1]
data = {'key': key,
'default': default,
'help_text': help_text,
'value': getattr(config, key)}
setting_list.append(data)
return setting_list
in urls.py:
router.register(r'setting', SettingViewSet, base_name='setting')
ask get http://x.x.x.x/setting/
you can get:
[
{
"key": "staff_prefix",
"default": "",
"help_text": "工号固定代码",
"value": ""
},
{
"key": "staff_suffix",
"default": 3,
"help_text": "工号尾缀",
"value": "3"
}
]
post http://x.x.x.x/setting/
with data {'staff_prefix': 'demo'}
you can update value in staff_prefix
.
You can also do the same with a serializer if you using database backend:
serializer.py:
from constance.backends.database.models import Constance
from constance import config
from django.conf import settings
from rest_framework import serializers
class ConfigSerializer(serializers.ModelSerializer):
default = serializers.SerializerMethodField()
help_text = serializers.SerializerMethodField()
value = serializers.SerializerMethodField()
class Meta:
model = Constance
fields = ('key', 'default', 'help_text', 'value')
def get_default(self, obj):
default, _ = settings.CONSTANCE_CONFIG.get(obj.key)
return default
def get_help_text(self, obj):
_, help_text = settings.CONSTANCE_CONFIG.get(obj.key)
return help_text
def get_value(self, obj):
return getattr(config, obj.key, None)
views.py:
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated
from constance.backends.database.models import Constance
from myproject.apps.common.api.v1.serializers import ConfigSerializer
class ConfigAPIView(ReadOnlyModelViewSet):
serializer_class = ConfigSerializer
permission_classes = [IsAuthenticated]
queryset = Constance
urls.py:
from django.urls import path
from myproject.apps.common.api.v1.views import ConfigAPIView
urlpatterns = [
path(
"config/",
ConfigAPIView.as_view({"get": "list"}),
name="config-list",
),
]
I am building a project in which I need to have a few custom settings that are editable by certain users which do not have access to the django admin panel, who access the application via an Angular frontend.
I installed django-constance in order to have these custom settings editable, as it was the most recommended package I could find on the Django packages site. My problem now is that I do not know how to do to serve the settings on my API rest.
I started with some customized view:
class ConstanceSettingSerializer(serializers.Serializer):
name = serializers.CharField()
value = serializers.Field()
defult_value = serializers.Field()
modified = serializers.BooleanField(read_only=True)
from constance import settings as constance_settings
class ConstanceView(APIView):
def get(self, request):
settings = constance_settings.CONFIG.items()
return Response(settings, status=status.HTTP_200_OK)
But now I dont know how to pass those settings correctly to my serializer. I tried this without success:
settings_serializer = ConstanceSettingSerializer(settings)
return Response(settings_serializer.data, status=status.HTTP_200_OK)
And I am only getting errors.
Some idea how to do this properly?
Thanks!
Your serializer needs to know what to return. So for each field, you can do something like this:
class ConstanceSettingSerializer(serializers.Serializer):
setting_name = serializers.SerializerMethodField()
def get_setting_name(self):
settings = constance_settings.CONFIG.items()
# Retrieve your setting's value here and return
return setting_value
That’s on the way out. If you wanted to be able to change settings via PUT/POST/PATCH, you need to override create/update in your serializer and implement the logic to save the values yourself.
Another way could be to check how the storage of the settings is implemented.
I have not used the constance settings so i cant say. But if it uses DB to store the settings, you can implement model serializer for the model which they use.
Give you a demo
from .utils import get_settings
from constance import config
from rest_framework.viewsets import ViewSet
class SettingViewSet(ViewSet):
permission_classes = (IsAuthenticated,)
def setting(self, request, allow_settings):
if request.method == 'GET':
# list all setting items
return Response(data=get_settings(allow_settings))
else:
# change all allow setting items in allow_settings
for key in request.data:
if key in allow_settings and key in getattr(settings, 'CONSTANCE_CONFIG', {}):
value = request.data[key]
setattr(config, key, '' if value is None else value)
return Response(data=get_settings(allow_settings))
def create(self, request):
"""
<p>update with POST:<code>{'Key': new_value}</code>
"""
allow_settings = [key for key, options in getattr(settings, 'CONSTANCE_CONFIG', {}).items()]
return self.setting(request, allow_settings)
def list(self, request):
"""
get all setting item
"""
allow_settings = [key for key, options in getattr(settings, 'CONSTANCE_CONFIG', {}).items()]
return self.setting(request, allow_settings)
in utils.py:
def get_settings(allow_settings):
setting_list = []
for key, options in getattr(settings, 'CONSTANCE_CONFIG', {}).items():
if key in allow_settings:
default, help_text = options[0], options[1]
data = {'key': key,
'default': default,
'help_text': help_text,
'value': getattr(config, key)}
setting_list.append(data)
return setting_list
in urls.py:
router.register(r'setting', SettingViewSet, base_name='setting')
ask get http://x.x.x.x/setting/
you can get:
[
{
"key": "staff_prefix",
"default": "",
"help_text": "工号固定代码",
"value": ""
},
{
"key": "staff_suffix",
"default": 3,
"help_text": "工号尾缀",
"value": "3"
}
]
post http://x.x.x.x/setting/
with data {'staff_prefix': 'demo'}
you can update value in staff_prefix
.
You can also do the same with a serializer if you using database backend:
serializer.py:
from constance.backends.database.models import Constance
from constance import config
from django.conf import settings
from rest_framework import serializers
class ConfigSerializer(serializers.ModelSerializer):
default = serializers.SerializerMethodField()
help_text = serializers.SerializerMethodField()
value = serializers.SerializerMethodField()
class Meta:
model = Constance
fields = ('key', 'default', 'help_text', 'value')
def get_default(self, obj):
default, _ = settings.CONSTANCE_CONFIG.get(obj.key)
return default
def get_help_text(self, obj):
_, help_text = settings.CONSTANCE_CONFIG.get(obj.key)
return help_text
def get_value(self, obj):
return getattr(config, obj.key, None)
views.py:
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated
from constance.backends.database.models import Constance
from myproject.apps.common.api.v1.serializers import ConfigSerializer
class ConfigAPIView(ReadOnlyModelViewSet):
serializer_class = ConfigSerializer
permission_classes = [IsAuthenticated]
queryset = Constance
urls.py:
from django.urls import path
from myproject.apps.common.api.v1.views import ConfigAPIView
urlpatterns = [
path(
"config/",
ConfigAPIView.as_view({"get": "list"}),
name="config-list",
),
]