I have this REST API:
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', UserViewSet.as_view({'get': 'list',
'post': 'create',
'delete': 'delete'})),
path('users/<uuid:pk>/video/', UserViewSet.as_view({'post': 'video'}))
]
How can i rewrite this with routers?
Default router with register method creates API -> GET users/ and POST users/ and also DELETE /users/{id} but it's different from current, because i need DELETE /users/ endpoint.
Or, maybe, in this situation it would be more correct to use my code with dictionaries?
assuming that UserViewSet is indeed a viewset, you can use the restframework's default router to register the router for /users/, and then add an action to handle you /video/ route from that viewset.
urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users/', UserViewSet, basename='users')
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls
viewsets.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import (
CreateModelMixin, RetrieveModelMixin,
DestroyModelMixin, ListModelMixin
)
from rest_framework.decorators import action
from rest_framework.parsers import MultiPartParser
class UserViewSet(CreateModelMixin, RetrieveModelMixin,
DestroyModelMixin, ListModelMixin, GenericViewSet):
# serializer class
# queryset
# permissions
#action(methods=['post'], parser_classes=(MultiPartParser,), detail=True)
def video(self, request, pk=None, *args, **kwargs):
# Implementation to upload a video
Edit
To create a bulk DELETE of users endpoint, I would create a Mixin class, as there is no django mixin for Deleting on the index of a router..
class BulkDeleteModelMixin:
def destroy(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
self.perform_destroy(queryset)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data,
status=status.HTTP_201_CREATED, headers=headers)
def perform_destroy(self, queryset):
queryset.delete()
And inherit from this class in your viewset
viewsets.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import (CreateModelMixin, RetrieveModelMixin, ListModelMixin)
from some_app.mixins import BulkDeleteModelMixin
class UserViewSet(CreateModelMixin, RetrieveModelMixin,
BulkDeleteModelMixin, ListModelMixin, GenericViewSet):
Related
views.py
from django.shortcuts import render
from rest_framework import viewsets
from django.http import HttpResponse
from .serializers import TodoSerializer
from .serializers import UserSerializer
from .models import Todo
from .models import User
class TodoView(viewsets.ModelViewSet):
serializer_class = TodoSerializer
queryset = Todo.objects.all()
def get_object(request):
return "Added";
class UserView(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
def get_object(request):
print("request", request)
return "Registered";
class LoginView(viewsets.ModelViewSet):
#serializer_class = UserSerializer
#queryset = User.objects.all()
#print("queryset = ",queryset[len(queryset)-1].email_id)
#print("serializer_class = ",serializer_class)
def get_object(self,request):
return HttpResponse("request")
# Create your views here.
urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from todo import views
router = routers.DefaultRouter()
router.register(r'users', views.UserView)
router.register(r'todos', views.TodoView)
router.register(r'login', views.LoginView)
print("In url file")
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
]
This is my views.py file and urls.py file.
I have a model created for user, with fields- email_id and password
CRUD operations are implemented automatically, so how do I validate data passed from the login form in frontend
Please tell me what's wrong in the code. I am not able to do the login part.
I am working of django rest framework api_root. It cannot find view even though I name it.
# board/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import BoardList, BoardDetail, api_root
app_name = 'board'
urlpatterns = [
path('boards/', BoardList.as_view(), name='board-list'), # board-list
path('boards/<int:pk>', BoardDetail.as_view(), name='board-detail'),
path('', api_root),
]
urlpatterns = format_suffix_patterns(urlpatterns)
# board/views.py
from django.contrib.auth.models import User
from django.shortcuts import render
from rest_framework import generics, permissions, serializers
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from .models import Board
from .serializers import BoardSerializer
from .permissions import IsAuthorOrReadOnly
#api_view(['GET'])
def api_root(request, format=None):
return Response({
'boards': reverse('board-list', request=request, format=format) # board-list
})
class BoardList(generics.ListCreateAPIView):
queryset = Board.objects.all()
serializer_class = BoardSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
It throws error,
Reverse for 'board-list' not found. 'board-list' is not a valid view function or pattern name.
Why it cannot find view name?
Since you included an app_name in your urls.py, you need to specify the view name with the app name, so:
#api_view(['GET'])
def api_root(request, format=None):
return Response({
'boards': reverse('board:board-list', request=request, format=format) # board-list
})
I'm relatively new to Django & Django rest - previously built only very simple apps.
Currently facing a problem with using a nested routes.
Here are my related configs:
main urls.py:
urlpatterns = [
url(r'^'+root_url+'/swagger', swagger_schema_view),
url(r'^' + root_url + '/', include('payments.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
app's urls.py:
urlpatterns = [
url(r'payments', views.PaymentsView.as_view(), name='index'),
url(r'payments/charge', views.PaymentsChargeView.as_view(), name='charge'),
]
app's views:
import logging
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.authentication import BasicAuthentication
from mysite.csrf_exempt import CsrfExemptSessionAuthentication
from rest_framework.views import APIView
from rest_framework.response import Response
import stripe
try:
from django.conf import settings
except ImportError:
pass
logger = logging.getLogger(__name__)
#method_decorator(csrf_exempt, name='dispatch')
class PaymentsView(APIView):
authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
def get(self, request, *args, **kwargs):
print('here GET PaymentsView')
return Response('good')
def post(self, request, *args, **kwargs):
print('here POST PaymentsView')
return Response('good')
#method_decorator(csrf_exempt, name='dispatch')
class PaymentsChargeView(APIView):
authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
def get(self, request, *args, **kwargs):
print('here GET PaymentsChargeView')
return Response('good')
def post(self, request, *args, **kwargs):
print('here POST PaymentsChargeView')
return Response('good post')
Problem:
requests both to /payments and /payments/charge GET/POST always processed by PaymentsView (ex: POST to /payments and to /payments/charge gives me 'here POST PaymentsView' in console)
The best practice is to put $ (end-of-string match character) in your url. So the defined url will match and process the correct view function.
url(r'payments$', views.PaymentsView.as_view(), name='index'),
url(r'payments/charge$', views.PaymentsChargeView.as_view(), name='charge'),
change your url order
urlpatterns = [
url(r'payments/charge', views.PaymentsChargeView.as_view(), name='charge'),
url(r'payments', views.PaymentsView.as_view(), name='index'),
]
urlpatterns = [
url(r'^payments', views.PaymentsView.as_view(), name='index'),
url(r'^payments/charge', views.PaymentsChargeView.as_view(), name='charge'),
]
I'm missing something, but I don't know what it is. When I go to the DRF Viewer, alerts is not listed in the possible list of urls. all the other Rest URLs do.
here's my serializer.py:
class OptionSerializer(serializers.ModelSerializer):
class Meta:
model = Options
fields = '__all__'
validators = [
UniqueTogetherValidator(
queryset=Options.objects.all(),
fields=('Member', 'skey', 'Time_Period')
)
]
api.py:
class OptionViewSet(generics.ListCreateAPIView):
serializer_class = OptionSerializer
def get_queryset(self):
"""
This view should return a list of all the options
for the currently authenticated user.
"""
user = self.request.user
return Options.objects.filter(Member=user)
and my urls.py:
router = routers.DefaultRouter()
router.register(r'users', api.UserViewSet)
router.register(r'groups', api.GroupViewSet)
router.register(r'currency', api.BitCoinViewSet)
router.register(r'latest_prices', api.CurrencyLatestViewSet)
router.register(r'options', api.OptionViewSet.as_view, 'alerts')
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Why does the alert url not show up? Thanks.
Routers only work with ViewSets, but your OptionViewSet is an ordinary APIView.
You should be able to fix it by just using the appropriate mixins and base class:
class OptionViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
serializer_class = OptionSerializer
def get_queryset(self):
"""
This view should return a list of all the options
for the currently authenticated user.
"""
user = self.request.user
return Options.objects.filter(Member=user)
How do you use Django Rest Framework to create an API when the data model has a composite key consisting of two fields? Background: I am trying to make a REST api for a data model (sample data row below- first two entries make the composite key). I am able call upon my data with date field but am getting errors when I try to use the second string field to return a single record.
'2015-05-06','INTC','31.93','32.79','32.50','32.22','31737537'
I am trying to make the api url structure like so:
localhost/api/v1/yyyy-mm-dd/'char'
localhost/api/v1/2015-05-07/AAPL
serializers.py
from rest_framework import serializers
from .models import Stocksusa, Optionsusa
from rest_framework.reverse import reverse
class StocksUsaSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.SerializerMethodField('get_stock_usa_url')
def get_stock_usa_url(self, obj):
values = [obj.Trade_Date, obj.Ticker]
composite_key_url = "http://0.0.0.0:9978/api/v1/stocksusa/{}/{}".format(*values)
return composite_key_url
class Meta:
model = Stocksusa
fields = ('Trade_Date', 'Ticker', 'PxMin', 'PxMax', 'PxOpen', 'PxClose', 'Volume', 'url')
views.py
from django.shortcuts import render
from rest_framework import authentication, permissions, viewsets, filters
from .models import Stocksusa
from .serializers import StocksUsaSerializer
from django.contrib.auth import get_user_model
User = get_user_model()
class DefaultsMixin(object):
authentication_classes = (
authentication.BasicAuthentication,
authentication.TokenAuthentication,
)
permission_classes = (
permissions.IsAuthenticated,
)
paginate_by = 25
paginate_by_param = 'page_size'
max_paginate_by = 100
filter_backends = (
filters.DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter,
)
class StocksUsaViewSet(DefaultsMixin, viewsets.ReadOnlyModelViewSet):
queryset = Stocksusa.objects.all()
serializer_class = StocksUsaSerializer
app/urls.py
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter(trailing_slash=False)
router = DefaultRouter()
router.register(r'stocksusa', views.StocksUsaViewSet)
urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf.urls import include, url
from rest_framework.authtoken.views import obtain_auth_token
from FinDataUsa.urls import router
from FinDataUsa.views import StocksUsaViewSet as stockview
urlpatterns = patterns('',
url(r'^api/token/', obtain_auth_token, name='api-token'),
url(r'^api/v1/', include(router.urls)),
url(r'^api/v2/', include(router.urls)),
url(r'^admin/', include(admin.site.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^docs/', include('rest_framework_swagger.urls')),
)
The problem lies into the fact that the DefaultRouter uses the id lookup_field of your model for getting the object you want: For example this works:
GET localhost/api/v1/stocksusa/1
In order to provide extra parameters you need to hand-craft the urls like this:
url(r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})/(?P<code>\w+)$',
StocksUsaViewSet.as_view(),
name='stocks_detail'
),
The year month day code parameters are passed into your view with the kwargs dictionary:
self.kwargs['year']
self.kwargs['month']
self.kwargs['day']
self.kwargs['code']
On your get_object method you need to do something like that:
def get_object(self, queryset=None):
try:
date= datetime.date(
year=int(self.kwargs['year']),
month=int(self.kwargs['month']),
day=int(self.kwargs['day']),
)
except ValueError:
raise Http404
stock= get_object_or_404(Stocksusa, Ticker=self.kwargs['code'], Trade_Date=date)
return stock
Then you will have access to your object: