4

Taking my first steps in django here, building a simple crud api where i have two entities: device and property.

my project urls.py looks like this:

from django.contrib import admin
from django.urls import include, path
from devices.views import index

urlpatterns = [
    path('', index, name='index'),
    path('admin/', admin.site.urls),
    path('api/', include('devices.urls')),
]

and my app urls.py as follows:

from django.urls import path
from . import views

urlpatterns = [
    path('device/create/', views.DeviceCreate.as_view()),
    path('device/update/<int:pk>/', views.DeviceUpdate.as_view()),
    path('device/delete/<int:pk>/', views.DeviceDelete.as_view()),
    path('device/', views.DeviceList.as_view()),
    path('device/<int:pk>/', views.DeviceDetail.as_view()),

    path('property/create/', views.PropertyCreate.as_view()),
    path('property/update/<int:pk>/', views.PropertyUpdate.as_view()),
    path('property/delete/<int:pk>/', views.PropertyDelete.as_view()),
    path('property/', views.PropertyList.as_view()),
    path('property/<int:pk>/', views.PropertyDetail.as_view()),
]

which is somewhat repetitive but ok, the real problem is my views file is far more repetitive:

from rest_framework import generics

from .models import Device, Property
from .serializers import DeviceSerializer, PropertySerializer

from django.shortcuts import render

def index(request):
    return render(request, 'index.html')

class DeviceCreate(generics.CreateAPIView):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

class DeviceList(generics.ListAPIView):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

class DeviceUpdate(generics.UpdateAPIView):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

class DeviceDelete(generics.DestroyAPIView):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

class DeviceDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

class PropertyCreate(generics.CreateAPIView):
    queryset = Property.objects.all()
    serializer_class = PropertySerializer

class PropertyList(generics.ListAPIView):
    queryset = Property.objects.all()
    serializer_class = PropertySerializer

class PropertyUpdate(generics.UpdateAPIView):
    queryset = Property.objects.all()
    serializer_class = PropertySerializer

class PropertyDelete(generics.DestroyAPIView):
    queryset = Property.objects.all()
    serializer_class = PropertySerializer

class PropertyDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Property.objects.all()
    serializer_class = PropertySerializer

i looked over the web for example's and it does seem like a valid way (plus my app is working) but is there a way to improve my views.py file to get the same result with less code?

3
  • You should consider executing the tutorial from start to end.You would have found ViewSets which would help make your code more compact. Commented Aug 22, 2018 at 8:36
  • so the tutorial didn't include viewSets but it does have a link to a farther tutorial about this topic, which i'll definitely use now ,thanks Commented Aug 22, 2018 at 9:10
  • I don't understand. Isn't django-rest-framework.org/tutorial/6-viewsets-and-routers part of the tutorial ? Commented Aug 22, 2018 at 10:37

2 Answers 2

4

You can use one ModelViewSet for your PropertySerializer and one for your DeviceSerializer

The ModelViewSet provides default create, retrieve, update, partial_update, destroy, and list actions.

Your views wil look like this:

class DeviceViewSet(ModelViewSet):
    serializer_class = DeviceSerializer

    def get_queryset(self):
        return Device.objects.all()


class PropertyViewSet(ModelViewSet):
    serializer_class = PropertySerializer

    def get_queryset(self):
        return Property.objects.all()

You wil then register your views with a router in your urls.py as follow:

from . import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'devices', views.DeviceViewSet, base_name='device')
router.register(r'properties', views.PropertyViewSet, base_name='property')
urlpatterns = router.urls

Note that your serializer class would then also have to be a ModelSerializer:

class DeviceSerializer(ModelSerializer):
    class Meta:
        model = Device
        fields = ('foo', 'bar')


class PropertySerializer(ModelSerializer):
    class Meta:
        model = Device
        fields = ('foo', 'bar')

You can read more about this in the rest framework docs

Sign up to request clarification or add additional context in comments.

Comments

1

You should use ModelViewSet from rest_framework in such case, f.e. for devices it would be one ViewSet as shown below:

class DeviceViewSet(viewsets.ModelViewSet):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

then in your urls.py

from myapp.views import DeviceViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'device', DeviceViewSet, base_name='device')
urlpatterns = router.urls

The main difference is that you have the same endpoint for different operations. They are distinguished by HTTP methods, f.e.

  • GET /devices would be equal to your DeviceList
  • GET /devices/<id> would be equal to your DeviceDetail
  • POST /devices would be equal to your DeviceCreate
  • PUT /devices/<id> would be equal to your DeviceUpdate
  • DELETE /devices/<id> would be equal to your DeviceDelete

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.