Pass List of UUID to django endpoint url as param - django

I have this code
#VIEWS
def report_pdf(request, queryset):
if request.method == "GET":
trans = Transaction.objects.filter(id__in=queryset)
return something
#URLS
path("pdf/<uuid:queryset>", views.report_pdf, name="get_pdf")
#FRONT END
const handlePDFDownload = (ids) => {
const body = ids
axios.get(`/calc/pdf/`,body , {
responseType: 'blob',
}).then(res => {
fileDownload(res.data, 'filename.zip');
console.log(res, 'downloading');
}).catch(err => {
console.log(err);
})
}
Now from my frontend react iam sending a get request to this endpoint with a list of UUID values.
I cant find a way to access that list in my view coming from frontend.
Would appreciate any suggestions!

I would suggest you pass the uuids as query params to the url as
../pdf?queryset=<uuids here>
then get the list in your view as
queryset = request.GET.get('queryset')
and then use queryset further in view.

You are sending list of uuid's from frontend but in your urls expects one uuid so that you need to change it like this:
urls.py:
path("pdf/", views.report_pdf, name="get_pdf")
views.py:
def report_pdf(request):
if request.method == "GET":
uuid_list = request.GET.getlist("queryset[]")
trans = Transaction.objects.filter(id__in=uuid_list)
return something

Related

Show loading gif until the django view performs the data processing and renders the template with this data

I have a django project where the page has multiple nav links representing different agents. On clicking any nav link, the urls.py redirects to nav specific view and the view needs to perform some processing to get the data needed to render the template. However as this is syncrhonous rendering it takes a long while to load data (in the order of 15-20s).
Below is my urls.py:
from django.urls import path
from . import views
app_name = 'agent'
urlpatterns = [
path('agent1/', views.agent1, name='agent1'),
path('agent2/', views.agent2, name='agent2'),
path('agent3/', views.agent3, name='agent3'),
path('agent4/', views.agent4, name='agent4'),
]
My views method looks as below:
def agent1(request):
agent_data = Agent1.objects.all()
agent_details = get_agent_details(agent_data)
return render(request, 'manager/data.html', {'agent_data': agent_data, 'agent_details': agent_details})
I am using the {{ agent_data.name }}, {{ agent_data.code }}, {{ agent_data.qty }} and {{ agent_data.price }} along with data from agent_details dictionary in my html to populate a table's rows. How should I change my view method, so that it loads the data via AJAX (javascript) in order to show a loading gif in the meantime and also provide me the data so that I can populate the table. Could someone help me with the Ajax code and the steps as I am new to this technology and not finding any help going through the online tutorials.
So for this to work with ajax, you'll need some javascript in manager/data.html which knows the url to fetch data from.
As an example, I've got an ajax setup which checks a given email address isn't already in use;
(function($) {
$(document).ready(function() {
var validateEmailURL = $section_user_signup.data('ajax-email-url');
function validateEmailUnique() {
var valid = true;
clearError($email);
// Fetch unique status of the provided email
$.ajax({
async: false,
url: validateEmailURL,
method: 'POST',
type: 'POST',
dataType: 'json',
data: {
'email': $email.val(),
'csrftoken': $form.find('input[name="csrfmiddlewaretoken"]').val()
},
success: function (response) {
valid = true;
},
error: function (response) {
setError($email, response["responseJSON"]["error"]);
valid = false;
}
});
return valid;
}
});
})(window.jQuery);
This javascript uses the data attribute of a div for the URL to check;
<div data-ajax-email-url="{% url 'account_ajax_validate_email' %}">
The view which the ajax call goes to looks like this;
def ajax_check_email_unique(request, *args, **kwargs):
"""
Return an JsonResponse to identify if an email is unique.
"""
if not request.is_ajax():
return HttpResponseBadRequest()
if request.is_ajax and request.method == "POST":
email = request.POST.get('email')
if email_address_exists(email):
return JsonResponse(
{
"error":
"Email address already exists. Click "
f"here "
"to login"
},
status=400
)
return JsonResponse(
{"email": email},
status=200
)
# some error occurred
return JsonResponse({"error": ""}, status=400)
The important thing for any view which will be used by javascript is that you return a JsonResponse.
So if I was you, I'd setup a new view for ajax, and that makes your existing one really simple;
def agent1_ajax(request):
agent_data = Agent1.objects.all()
agent_details = get_agent_details(agent_data)
return JsonResponse({
"agent_data": agent_data, "agent_details": agent_details
}, status=200)
def agent1(request):
return render(request, 'manager/data.html', {})
And as far as a loading gif goes, you'd need an element that contains the gif and then you can bind to the ajax event to show/hide;
$(document).ajaxStart(function() {
$("#loading").show();
});
$(document).ajaxStop(function() {
$("#loading").hide();
});

Sending Django requests to NextJS with data

I am looking at integrating NextJS into an existing Django project. The project makes heavy use Django templates for most of its pages and I am looking at modernising the project by taking advantage of React and building out a design / component system. The idea is that we would look at replacing Django with NextJS eventually.
I have been able to use Django to proxy a request through to NextJS, and it works great! I have also been able to send data directly to the NextJS route so that I do not have to call back to Django to get data. This approach annoyingly has the limitation of only sending key/value data.
Here is the working code.
# django
def get(self, request, *args, **kwargs):
data = request.GET
return self._handle_request(data, requests.post)
def _handle_request(self, data, make_request):
data = {"hello": "world"}
response = make_request("http://localhost:3000", data=data)
return HttpResponse(response)
//nextjs
import parse from "urlencoded-body-parser";
export async function getServerSideProps(context) {
const { req } = context;
const props = await parse(req);
return { props };
};
So with this in mind, is there a better way to achieve sending data to a NextJS route without having to do a callback?
After some research I was able to achieve this by using application/json content type.
class NextJsView(WhiteLabelMixin, View):
def get(self, request, *args, **kwargs):
data = request.GET
return self._handle_request(data, requests.post)
def _handle_request(self, data, make_request):
data = {"hello": {"dark": "world"}}
response = make_request("http://localhost:3000", json=json.dumps(data))
return HttpResponse(response)
import getRawBody from "raw-body";
export async function getServerSideProps(context) {
const { req } = context;
let props = {};
if (req.method == "POST") {
const body = await getRawBody(req);
props = JSON.parse(JSON.parse(body));
}
return { props };
}

Django : Calling a Url with get method

I have the url and corresponding view as follows.
url(r'^(?P<token>.*?)/ack$', views.api_ACK, name='device-api_ack')
def api_ACK(request, token):
"""
Process the ACK request comming from the device
"""
logger.info('-> api_ACK', extra={'request': request, 'token' : token, 'url': request.get_full_path()})
logger.debug(request)
if request.method == 'GET':
# verify the request
action, err_msg = api_verify_request(token=token, action_code=Action.AC_ACKNOWLEDGE)
return api_send_answer(action, err_msg)
I want to call api_ACK function with request method as GET from another view api_send_answer
I am creating one url in /device/LEAB86JFOZ6R7W4F69CBIMVBYB9SFZVC/ack in api_send_answer view as follows..
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
response = api_ACK(request=url,token=last_action.next_token) # This is wrong
Now from api_send_answer it is redirecting to api_ACK view, but how to call api_ACK with request method as GET?
Please help..Any suggestions would be helpful to me
This line
response = api_ACK(request=url,token=last_action.next_token) is wrong because view expects HttpRequest object and you give him url instead.
if you need to return view response to user, you can use redirect:
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
return HttpResponseRedirect(url)
if you need to do something else with view response you have to use HttpRequest object not url as parameter.

can't call django json view with angularjs

i'm new in django and also in angularjs.
I wants to use Django for a REST api and angularjs for frontend view.
I have a django view that returns a json response:
class MyView(View):
def get(self, request):
data = serializers.serialize('json', MyModel.objects.order_by('name'))
return HttpResponse(data, mimetype='application/json')
def options(self, request):
response = HttpResponse()
response['allow'] = ','.join(['get', 'post', 'put', 'delete', 'options'])
return response
calling
http://localhost:8000/myapp/myview
i get the right json response
If in an angularjs controller (controllers.js) i try to call that view like this:
angular.module('myApp.controllers', []).
controller('MyCtrl', ['$scope', '$http', function($scope, $http) {
$scope.test = "Hola";
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('http://localhost:8000/myapp/myview').success(function(data) {
$scope.results = data;
console.log(data);
}).error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
console.log(data);
});
}]);
"test" value is correctly printed in the template
in django log i have: "GET /myapp/myview/ HTTP/1.1" 200 853
but in angular i don't retrieve any data. If i put a break point in error method, i have data empty and status = 0.
Any hints?
Am i missing something?
Been struggling with the same. The problem is with CORS. The solution is here
$http.get('http://localhost:8000/myapp/myview/').success(function(data)
The URL needs to drop the trailing /, then append .json. Like so:
$http.get('http://localhost:8000/myapp/myview.json').success(function(data)

Is it possible to return an HttpResponse in django with text & a json object?

In my view function, I'd like to return a json object (data1) and some text/html (form). Is this possible?
Here is part of my views.py:
if request.is_ajax() and request.method == 'POST':
...
if form.is_valid():
answer = form.cleaned_data['answer'] # Answer extracted from form is also a string
a1 = ques1.correct_answer
if a1 == answer:
test1 = question_list.get(id=nextid)
form = AnswerForm(test1)
ques1 = question_list.filter(id=nextid) # Filter next question as <qs>
data1 = serializers.serialize("json",ques1) # Json-ize
# ********EDITED HERE **********
variables1 = Context({
'form' : form,
'q1' : data1,
})
#response = HttpResponse()
#response['data1'] = response.write(data1)
#response['form'] = response.write(form)
if nextid <= qsnlen:
return HttpResponse(variables1, mimetype="application/json")
#return HttpResponse(response)
else:
...
I'd like to send back both the form html and the ques1 json object. How can I do this? Thanks in advance.
Just put both pieces of data in a JSON container, one key with the form data and one with the HTML as a rendered string. In the browser, you can just pull both keys out & do your thing.
In your view:
form_json_data = get_form_json_data()
rendered_html = get_the_html()
return HttpResponse(json.dumps({
"formdata": form_json,
"html": rendered_html}),
content_type="application/json")
In js:
$.post(foo, postdata, function(data){
var formdata = data.formdata
var html = data.html;
$(".html-target").replaceWith(html);
do_whatever(formdata);
})
Use JsonResponse
from django.http import JsonResponse
response_data = {put your data into a dict}
return JsonResponse(response_data, status=201)
To do this with one response; you need to send the JSON as a plain text in the context of your template response (HTML).
If you need to send JSON as as a separate JSON object, with its own mime type, then you need to write two views; one that sends back the JSON as application/json and the other that sends back the form (HTML).
EDIT:
You are not returning JSON objects, but you are turning a dictionary that has two items of two different types. As I explained in the comments, in one request/response cycle; you can only return one response which has a specific mime type that is based on the content and how you want the browser to handle it. Most of the time the content type is 'text/html'.
In your scenario, if you want to return both the HTML (which is your form), and the JSON response (which is a string), you need to return HTML.
If you want to return JSON to Jquery as a JSON object; you need to detect the request type. In your front end (the templates), you will initiate two requests - one from the browser, which will return back the form. The other from jQuery, which will return the appropriate JSON object.
Here is a possible approach to this:
def foo(request):
if request.is_ajax():
ctx = dict()
ctx['hello'] = 'world'
return HttpResponse(json.dumps(ctx),content_type='application/json')
else:
return HttpResponse('hello world')