How to export csv file after search data in Django 2? - python

I have a search function that returns json via ajax, but I also want to export the data to a csv file.
It occurred to me to do another function to export the data, which brings the search function
I'm doing it like this:
def search(request):
date = request.GET.get('date')
queryset = List.objects.filter(date=date)
data = serializers.serialize('json', queryset)
return HttpResponse(data, content_type='application/json')
def export_to_csv(request):
data = search(request)
# But that does not bring the search data
print(data)
# <HttpResponse status_code=200, "application/json">
I hope you understand my question, some ideas or suggestions?

Maybe you can try with simply extracting the logic which retrieves and serializes the data into a helper function, which can be a part of your views.py (or, probably a better approach, moved to a helper/utility module) e.g.:
def get_search_data(date=None):
queryset = List.objects.all()
if date:
queryset = queryset.filter(date=date)
return serializers.serialize('json', queryset)
def search(request):
data = get_search_data(request.GET.get('date'))
return HttpResponse(data, content_type='application/json')
def export_to_csv(request):
data = get_search_data()
...
print(data)
# <HttpResponse status_code=200, "application/json">

Related

Downloading an Excel File in a Django View

I have included an excel file in my project directory. I want to created a Django view that allows a user to download that file. Please how best do I handle that?
import csv
from django.http import StreamingHttpResponse
# create an echo handler, returns what is put into for the writer
psuedo_buffer = Echo()
#Build csv writer ontop of echo filelike instance
writer = csv.writer(psuedo_buffer)
#Stream the response row by row using the psuedo_writer
response = StreamingHttpResponse((
writer.writerow(row) for row in query_data),
content_type="text/csv"
)
response['Content-Disposition'] = 'attachment; filename="Something.csv"'
return response
This is a code snippet that I use to return a streaming HTTP response with the data. The data that would be in query_data can either be raw CSV data from a file handler which you can pretty easily find a few ways to open the data and drop it into this function, or you can use arrays of data from query sets to pass in. Just format your data for query_set and return this Response handler in either API views or Template views. Hope this helps!
Data should be formatted in arrays of data, which you can use .dict to get parsable data from most models or simply parsing the csv into memory with the CSV library will accomplish the same thing.
Is your file associated with a Model? I prefer to create a Model to store general resources.
models.py
class Resources(models.Model):
description = models.CharField(max_length=200)
file = models.FileField(upload_to='uploads/resources/')
def __str__(self):
return self.description
views.py
...
some_file = Resources.objects.get(description='Your description')
...
return render(request, "template.html", {
"some_file": some_file,
}
template.html
...
<p>Download file.</p>
...

Passing data from post form to FileResponde view

I recently started using Django and I managed to create two views, one to submit a form and another to return a FileResponse, separately, they work fine.
Now, I need to integrate both, when the client submit the form, I want to redirect to the another view using the fields submitted at the previous form. How can I do that?
Here is my form view:
def submitForm(request):
if 'report' in request.POST:
date_start = request.POST.get('date_start')
date_end = request.POST.get('date_end')
state = request.POST.get('state')
return render(request, 'comissao.html')
Here is my view that creates a pdf file
def createPdf(request):
date_start = '20220301'
date_end = '20220331'
state = 'G00471'
body = "some html"
options = { 'quiet': '' }
pdfkit.from_string(body, options=options)
file = open('file.pdf', 'rb')
return FileResponse(file)
As you can see, I need the information passed at my first view, to use at second view, I tried something like this, but I think I'm mistaking the concept,
return reverse('pdf', kwargs={'state':state, 'date_start':date_start, 'date_end':date_end})
reverse() only returns the URL, but I think you rather want to do a redirect() to that view.
For passing the parameters you have several options:
GET parameters
Session
URL parameters
Let's use GET parameters, which I would suggest:
from urllib.parse import urlencode
...
def submitForm(request):
...
response = redirect('pdf')
params = { state' : state, 'date_start: date_start, 'date_end': date_end}
response['Location'] += f'?{urlencode(params)}'
return response
Then in your PDF view you need to parse the GET parameters:
def createPdf(request):
date_start = request.GET.get("date_start")
...
Note that you may also need to convert your dates into string and back for the query, which I ignored here.

Celery EncodeError(TypeError('Object of type Response is not JSON serializable'))

I am using Celery - Redis - Django rest framework together.
The error happens when I try to pass the serializer to the delay of celery within the Django rest framework.
Here is the viewset
class TestSet(viewsets.ModelViewSet):
queryset = Test.objects.all()
serializer_class = ImageSerializer
def create(self, request, *args, **kwargs):
serializer = TestSerializer(data=request.data)
if serializer.is_valid():
image_uploaded= "static_path"
json_data = base64.b64encode(np.array(image_uploaded)).decode('ascii')
result = test_call.delay({'image': json_data})
result = test_call.delay(serializer)
data = {"task": result.task_id}
return Response(data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#shared_task(name="values")
def test_call(decoded_image):
return decoded_image
The error I get is
EncodeError(TypeError('Object of type Response is not JSON
serializable'))
Update:
Even when I do this, I still get an error
result = test_call.delay({"task": 1})
#shared_task(name="values")
def test_call(decoded_image):
return {"task": 2}
This isn't going to answer your question, but I can't leave a comment (low reputation).
It seems that you are trying to JSON Serialize something that obviously isn't JSON serializable. Based on the name, it is some kind of image data. You could try a different workflow that should be JSON Serializable, example:
One Example:
first save the image somewhere that is accessible later and add the location in the serializer (S3 bucket and then a link to the image)
In your celery task, fetch the image data based on that location
Second Example:
convert the image data into something JSON serializable like a Base64 image string

Put Django view return data into response data

I have a function based view and it has many checks in it and returns data based on check results. So I don't want to wrap my data into Response object every time manually. Is there a way to put function return value into OK response data automatically in Django Rest Framework? For example to have a valid view like this:
#api_view(['GET'])
def pre_reg_countries(request):
if some_condition:
return data_1 # instead of returning Response(data=data_1)
else:
if another condition:
return data_2
else:
return []
P.S. The idea came to me from Java Spring framework.
If Django does not provide some built-in solution, a decorator like this can solve the problem:
def responsify(view_method):
def add_response(*args, **kwargs):
data = view_method(*args, **kwargs)
return Response(data)
return add_response

Prevent the Repetition of Data in Database

Here's the code in view,
def index(request):
data = Model.objects.create(user=request.user, timestamp=timezone.now())
Whenever the view is requested i'm saving the user requesting it & the timestamp at which user has requested the page.
But, It's repeating the same data in database with updated timestamp. How can I prevent the repetition by updating the same instance when the view is requested?
Please helpme!
You can handle using this way. If data is not there then create else update.
def index(request):
data = Model.objects.update_or_create(user=request.user, timestamp=timezone.now())
Alternatively:
def index(request):
data = Model.objects.get(user=request.user)
if not data:
data = Model.objects.create(user=request.user, timestamp=timezone.now())
else:
data = Model.objects.update(user=request.user, timestamp=timezone.now())

Categories