django rest-framework 单例视图集

django rest-framework singleton ViewSet

我需要通过 django rest_framework 将一组配置设置(键值对)传递给 api-enpoint。只读就好了。 Django 1.7,Python3 和 rest-framework v3.0.5.

我已经 pip install编辑了 django-solo,我可以在管理部分访问它,所以我认为它有效。我已经设置了一条有效的路线,现在我需要制作实际上 returns 数据的 'View-like-thing'。

据我所知(绝对错误):

class ConfigViewSet(mixins.ListModelMixin,
                    mixins.RetrieveModelMixin,
                    viewsets.GenericViewSet):

    model = SiteConfiguration
    permission_classes = (IsAuthenticatedOrReadOnly,)

    def get_serializer_class(self):
        # What goes here? I want _all_ the settings

    def get_object(self):
        obj = self.model.get_solo()
        self.check_object_permissions(self.request, obj)
        return obj

    def list(self, *args, **kwargs):
        return self.retrieve(*args, **kwargs) 

感谢任何帮助和提示。

PS!这是具有以下设置的 config/models.py

from django.db import models
from solo.models import SingletonModel

class SiteConfiguration(SingletonModel):
    site_name = models.CharField(max_length=255, default='Site Name')
    maintenance_mode = models.BooleanField(default=False)

    def __str__(self):
        return u"Site Configuration"

    class Meta:
        verbose_name = "Site Configuration"

Oki,开始了:

1) pip 安装 'django-solo'.

2) 使用 manage.py startapp config 创建一个新应用。

2a) 文件 config/models.py:

from django.db import models
from solo.models import SingletonModel

class SiteConfiguration(SingletonModel):
    site_name = models.CharField(max_length=255, default='Site Name')
    maintenance_mode = models.BooleanField(default=False)

    def __str__(self):
        return u"Site Configuration"

    class Meta:
        verbose_name = "Site Configuration"

2b) 文件 config/views.py:

from rest_framework.views import APIView
from rest_framework.response import Response

from .models import SiteConfiguration

config = SiteConfiguration.get_solo()    

class SiteConfiguration(APIView):
    permission_classes = []

    def get(self, request, format=None):
        """
        Return site configuration key-values.
        """
        return Response({
            'name': config.site_name
        })

3) 下一个问题是将视图添加到路由器。使用 DefaultRouter,无法注册 APIviews,所以这个人有一个简单的 HybridRouter 解决方案 [.

3a) 在您的项目文件夹(主 urls.py 文件所在的位置)中创建一个 custom_routers.py,内容如下:

from rest_framework import routers, views, reverse, response

class HybridRouter(routers.DefaultRouter):
    def __init__(self, *args, **kwargs):
        super(HybridRouter, self).__init__(*args, **kwargs)
        self._api_view_urls = {}

    def add_api_view(self, name, url):
        self._api_view_urls[name] = url

    def remove_api_view(self, name):
        del self._api_view_urls[name]

    @property
    def api_view_urls(self):
        ret = {}
        ret.update(self._api_view_urls)
        return ret

    def get_urls(self):
        urls = super(HybridRouter, self).get_urls()
        for api_view_key in self._api_view_urls.keys():
            urls.append(self._api_view_urls[api_view_key])
        return urls

    def get_api_root_view(self):
        # Copy the following block from Default Router
        api_root_dict = {}
        list_name = self.routes[0].name
        for prefix, viewset, basename in self.registry:
            api_root_dict[prefix] = list_name.format(basename=basename)
        api_view_urls = self._api_view_urls

        class APIRoot(views.APIView):
            _ignore_model_permissions = True

            def get(self, request, format=None):
                ret = {}
                for key, url_name in api_root_dict.items():
                    ret[key] = reverse.reverse(url_name, request=request, format=format)
                # In addition to what had been added, now add the APIView urls
                for api_view_key in api_view_urls.keys():
                    ret[api_view_key] = reverse.reverse(api_view_urls[api_view_key].name, request=request, format=format)
                return response.Response(ret)

        return APIRoot.as_view() 

3b) 在您的主要 urls.py 中执行此操作:

from .custom_routers import HybridRouter

# The rest is from the `rest-framework` polls-tutorial.

rest_router = HybridRouter()
rest_router.register(r'users', UserViewSet)
rest_router.register(r'polls', PollViewSet)
rest_router.add_api_view("config", url(r'^config/$', configViews.SiteConfiguration.as_view(), name='site_configuration'))

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [    
    url(r'^', include(rest_router.urls), name='rest_api'),    
    url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^admin/', include(admin.site.urls), name='admin'), 
]

所有这些似乎都适合我。

不需要外部依赖的替代方法:

# models.py

from django.db import models

class MySingleton(models.Model):
    
    def save(self, *args, **kwargs):
        self.pk = 1
        return super().save(*args, **kwargs)

    @classmethod
    def singleton(cls):
        obj, _ = cls.objects.get_or_create(pk=1)
        return obj

# serializers.py

from rest_framework import serializers

from . import models

class MySingletonSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.MySingleton
        fields = "__all__"
# views.py

from rest_framework import generics

from . import models
from . import serializers

class SingletonView(generics.RetrieveAPIView):
    serializer_class = serializers.MySingletonSerializer
    
    def get_object(self):
        return models.MySingleton.singleton()