Search code examples
djangocsvhttpresponsedjango-serializer

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)

Solution

  • 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