django rest : #api_view and #classmethod error - django

🚨 I desperately need #classmethod
i am use this code:
from rest_framework.response import Response
class MyClass():
#classmethod
#api_view(['GET', 'POST', 'PUT', 'DELETE'])
def CRUD(cls, request, id=0):
#.....
return Response({})
urlpatterns = [
re_path(r'^user/(?:(?P<id>[1-9]+)/)?$', UserView.CRUD)
]
get error:
The 'request' argument must be an instance of 'django.http.HttpRequest', not 'builtins.type'.
please help ; Thankful🙏🏻🙏🏻

Like #404pio said. Either you use a class based view or function based view. You cannot mix them.
class-based-view
from rest_framework.response import Response
from rest_framework.views import APIView
class MyClass(APIView):
def get(self, request, id):
# do stuff
return Response(...)
def post(self, request, id):
# do stuff
return Response(...)
.
.
.
urlpatterns = [
re_path(r'^user/(?:(?P<id>[1-9]+)/)?$', MyClass.as_view())
]
or
function-based-view
#api_view(['GET', 'POST'...])
def my_fbv(request, id):
if request.method == 'GET':
# do stuff
elif request.method == 'POST':
# do stuff
.
.
.
urlpatterns = [
re_path(r'^user/(?:(?P<id>[1-9]+)/)?$', my_module.my_fbv)
]

Related

How to redirect using a view name in Django, class-based views?

I have to redirect from one class-based View to another class-based View. I did it by:
return redirect('report')
but the suggestion was to redirect by View names. I did try this, but it doesn't work.
views.py:
class UploadView(View):
def get(self, request, *args, **kwargs):
Reservation.objects.all().delete()
template = "ReportApp/upload.html"
return render(request, template)
def post(self, request, *args, **kwargs):
# try:
csv_file = request.FILES['file']
data_set = csv_file.read().decode('UTF-8')
# setup a stream which is when we loop through each line we are able to handle a data in a stream
io_string = io.StringIO(data_set)
next(io_string)
for column in csv.reader(io_string, delimiter=',', quotechar="|"):
_ = Reservation.objects.update_or_create(
reservation_code=column[0],
checkin=column[1],
checkout=column[2],
flat=column[3],
city=column[4],
net_income=column[5],
)
# return redirect('report')
return redirect(ReportView.as_view())
upload_view = UploadView.as_view()
class ReportView(View):
def get(self, request, *args, **kwargs):
urls.py:
from .views import upload_view, report_view, city_commission_view, error_view
from django.urls import path
urlpatterns = [
path('upload', upload_view, name='upload'),
path('report', report_view, name='report'),
path('city_commission', city_commission_view, name='city_commission'),
path('error', error_view, name='error'),
]
any suggestions how to do this?
Not sure what you want to achieve and I do not see the code for class ReportView(View): def get(self, request, *args, **kwargs):
but perhaps you could try something like this:
from django.views.generic import RedirectView
class ReportView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
url_params = self.kwargs
and play with that.

Django - Make parameter optional

In my urls file, I have specified the path to views -
urlpatterns = [
path('users/userdetails', PersonalUserDetailView.as_view(), name='hello'),
path('stores/<int:store_id>', StoreDetailView.as_view(), name='hello2'),
]
Howvere, I want to make the store_id optional. How do I do it?
Set default arguments in view methods
class StoreDetailView(...):
def get(self, request, store_id=None):
...
def post(self, request, store_id=None):
...
Also, you need to update the URL patterns a bit,
urlpatterns = [
path('users/userdetails', PersonalUserDetailView.as_view(), name='hello'),
path('stores/&ltint:store_id>', StoreDetailView.as_view(), name='hello2'),
path('stores/', StoreDetailView.as_view(), name='hello-default'),
]
You can use regex non-capturing parenthesis, similar question here
from django.urls import re_path
urlpatterns = [
...
re_path(r'stores/(?:(?P<store_id>\d+)/)?$',StoreDetailView.as_view(), name="hello2"), # non-capture
]
class StoreAPIView(APIView):
def get(self, request, store_id=None):
if store_id is None:
qs = Store.objects.all()
return Reponse(.......)
else:
try:
store_obj = Store.objects.get(id=store_id)
serilized_data = StoreSerializer(store_obj).data
return Response(....)
except Exception as e:
return Response(...)
URLS
path('stores/<int:store_id>', StoreAPIView.as_view(), name='hello2')
You can also use viewsets which is much better:
from django.shortcuts import get_object_or_404
from myapps.serializers import StoreSerializer
from rest_framework import viewsets
from rest_framework.response import Response
class StoreViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Store.objects.all()
serializer = StoreSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Store.objects.all()
store = get_object_or_404(queryset, pk=pk)
serializer = StoreSerializer(store)
return Response(serializer.data)
urls.py
from myapp.views import StoreViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'stores', UserViewSet, basename='store')
urlpatterns = router.urls

Django Download csv after post request

I want to create an endpoint, in this endpoint its possible to send POST request, if the POST request
is validated, then the page download a csv
I created the serializer form to make a easy validation of the data received
My problem is that the csv its easy downloaded in a HttpResponse, but i need neccesary to make a endpoint and a validation of the data in a post request.
My principal problem is that i can´t return the export function next of the validation
This are my files
#urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^hello-view/', views.HelloApiView.as_view()),
]
Serializers
#serializers.py
from rest_framework import serializers
class HelloSerializer(serializers.Serializer):
"""Serializes a name field """
name = serializers.CharField(max_length=100)
seller_id = serializers.CharField(max_length=100)
def validate_name(self, dob):
UnitOfMeasureName = ["Each", "Grams", "Ounces", "Pounds", "Kilograms", "Metric Tons"]
if dob in UnitOfMeasureName:
return dob
else:
raise serializers.ValidationError('Wrong username')
And the views files
In this file i created the export function to try to export the csv data, but doesnt works
import csv
from django.shortcuts import render
from django.http import HttpResponse
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import serializers
class HelloApiView(APIView):
def export(self, request):
response = HttpResponse(content_type='text/csv')
writer = csv.writer(response)
writer.writerow(['First name', 'Last name', 'ID'])
response['Content-Disposition'] = 'attachment; filename="one.csv"'
return response
serializer_class = serializers.HelloSerializer
def get(self, request, format=None):
an_apiview = [
'Uses HTTP METHOD as function',
'Its is similar to a traditional django view'
]
return Response({'message': 'Hello', 'anapi': an_apiview})
def post(self, request):
serializer = serializers.HelloSerializer(data = request.data)
if serializer.is_valid():
in this place i want to return the file
else:
return Response(
serializer.errors, status = status.HTTP_400_BAD_REQUEST)
Add a new endpoint to your urls.py file
#urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^hello-view/', views.HelloApiView.as_view()),
url(r'^csv_download/$', views.csv_download, name="csv_download"),
]
Then in your views.py file, add a function called csv_download and move all of your stuff there (This might be unnecessary, but it sure makes for cleaner, more readable code)
# views.py
import csv
from django.shortcuts import render
from django.http import HttpResponse
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import serializers
class HelloApiView(APIView):
def get(self, request, format=None):
an_apiview = [
'Uses HTTP METHOD as function',
'Its is similar to a traditional django view'
]
return Response({'message': 'Hello', 'anapi': an_apiview})
def csv_download(request):
if request.method == 'POST':
serializer_class = serializers.HelloSerializer
serializer = serializers.HelloSerializer(data = request.data)
if serializer.is_valid():
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="one.csv"'
writer = csv.writer(response,delimiter=',') # I always like to specify the delimeter
writer.writerow(['First name', 'Last name', 'ID'])
#Then you may actually want to write some data to the CSV file, currently, you've only defined the headers (first row). An example would be like:
for value in list_of_objects:
writer.writerow([
value.first_name,
value.last_name,
value.id
])
return response
else:
return Response(
serializer.errors, status = status.HTTP_400_BAD_REQUEST)
else:
# redirect them or do something here if they hit this URL without a POST request

How do I combine multiple models into a single serializer?

it was necessary to combine several models(4) in one serializer, but there were problems with the implementation.
urls.py
from django.urls import path
from .views import FiltersView
urlpatterns = [
path('filters/' FiltersView.as_view(), name='Filters')
]
views.py
from rest_framework import views
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK
from .serializers import FiltersSerializers
class FiltersView(views.APIView):
def get(self, request, *args, **kwargs):
filters = {}
filters['model_1'] = Model1.objects.all()
filters['model_2'] = Model2.objects.all()
filters['model_3'] = Model3.objects.all()
serializer = FiltersSerializers(filters, many=True)
return Response (serializer.data, status=HTTP_200_OK)
serializers.py
from rest_framework import serializers
class FiltersSerializers(serializers.Serializer):
model_1 = Model1Serializers(read_only=True, many=True)
model_2 = Model2Serializers(read_only=True)
model_3 = Model3Serializers(read_only=True)
But on the output I get:
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{},
{},
{}
]
What could be the problem?
The way you are providing data to your serializer, many=True is not correct argument for it. Its a single object that you are passing to your serializer. Your view should be like this.
class FiltersView(views.APIView):
def get(self, request, *args, **kwargs):
filters = {}
filters['model_1'] = Model1.objects.all()
filters['model_2'] = Model2.objects.all()
filters['model_3'] = Model3.objects.all()
serializer = FiltersSerializers(filters)
return Response (serializer.data, status=HTTP_200_OK)

How can I call a function within a DRF view?

I am using Djano REST Framework for constructing APIs .I want something like below
def addTwoNumber(a,b):
return a+b
class MyView(viewsets.ModelViewSet):
def create(self, request, *args, **kwargs):
my_result=addTwoNumber(request.data.get('firstnum'),request.data.get('secondnum'))
return Response(data={"my_return_data":my_result})
That is , I want a view that doesn't deals with the queryset &serializer_class attributes. Is it possible ? Can anyone help me ?
Why are you using ModelViewSet? Just use APIView http://www.django-rest-framework.org/api-guide/views/
# views.py
from rest_framework.views import APIView
def addTwoNumber(a,b):
return a+b
class MyView(APIView):
def post(self, request, *args, **kwargs):
my_result=addTwoNumber(request.data.get('firstnum'),request.data.get('secondnum'))
return Response(data={"my_return_data":my_result})
# urls.py
urlpatterns = [
url(r'^myview/$', MyView.as_view()),
...
]