Django passing context in JsonResponse - python

I am developing a webpage with filters to filter the results on the page.
A Ajax is called, which sends the filters to my Django back-end. The results are filtered and the data should be passed back to the front-end.
So now I need to pass my results of the models with context to the front-end. This leads to some problems.
My Ajax:
$(document).on('change', '#test-form', function (e) {
e.preventDefault()
var tags = [];
$('input[name="tags[]"]:checked').each(function(i){
return tags[i] = $(this).val();
});
$.ajax({
type: 'POST',
cache: false,
url: "{% url 'core:jobSearch_nosearch' %}",
data: {
tags: tags,
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
},
success: function(data) {
console.log('yey')
console.log(data)
}
});
});
Here my View:
from django.core.serializers.json import DjangoJSONEncoder
from django.utils.functional import Promise
class LazyEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, Promise):
return str(obj)
return super().default(obj)
def jobSearch(request, **search):
companies = Company.objects.all()
if request.method == 'POST':
ads = Ad.objects.all()
search_job = request.GET.get('search')
if search_job:
ads = Ad.objects.filter(title__contains=search_job)
tag_filter = request.POST.getlist('tags[]')
for tag in tag_filter:
print(tag)
ads = ads.filter(tag__name=tag)
print(ads)
context = {'companies': companies, 'ads': ads}
# context = {'companies': list(companies)}
# context = {'msg': 'Success'}
# return JsonResponse(serialize('json', ads, cls=LazyEncoder), safe=False)
return JsonResponse(context)
else:
ads = Ad.objects.all()
context = {'companies': companies, 'ads': ads}
return render(request, 'core/jobSearch.html', context)
As you can see I tried different things in the my view. This return JsonResponse(serialize('json', ads, cls=LazyEncoder), safe=False) passes the result of one model. But I have two models which I have to pass to the front-end.
Additionally, I would like to get the data and being able to use it with the html template language.
In this way: (example)
{% for a in ads %}
{% a %}
{% endfor %}
Is that even possible with Django and Ajax, or is there another way to filter results and passing them without reloading the page?

django template tag work on rendering html content and you can not pass argument after render page so after loading page you can not use
{% for a in ads %}
{% a %}
{% endfor %}
if you have not pass that arguments
you can use api and js for this work
i suggest you read about drf
you can do this work with api and js

Related

Input value Set using jquery's selector does not post

There's this issue where I created a form using django. The form contains two charfields for name and address, and two datetimefields one for a start_date and the other for a stop_date. Finally there are two radio buttons, such that:
when the first is checked, the start_date field's value is set to date.now() using jquery's selector
when the second radio button is checked, the start_date and stop_date fields are disabled, still using jquery's selector.
The above code works well. However, when the start_date's value is successfully set, I have to post the form data using jquery ajax post method to a django view, the start_date's value is not posted at all, while the other field values are. I don't know how to go about this issue.
Here's my code:
template.html:
{% extends 'base.html' %}
<div class="center">
<form action="" invalidate>
{% crispy form form.helper %}
</form>
</div>
script.js:
$('input:radio').click(function){
if ($(this).val() === '1'){
var start_date = new Date();
$('#id_start_date').val(start_date);
}
else if ($(this).val() === '0'){ document.getElementById('id_stop_date').disabled = true;
document.getElementById('id_start_date').disabled = true;
}
}
$("form").on("submit", function (e){
var name = $("#id_name");
var type = $("id_type");
var start_date = $("id_start_date");
var stop_date = $("id_stop_date");
$.ajax({
type:"POST",
url:"{% url 'postAccount' %}",
data:{
csrfmiddlewaretoken: document.querySelector('input[name="csrfmiddlewaretoken"]').Val(),
name:name, type:type, start_date:start_date, stop_date: stop_date
},
contentType:"application/json; charset=utf-8",
dataType:"json",
success: function (response){
var response = JSON.parse(response ['instance']),
console.log(response);
}
});
e.preventDefault();
});
views.py:
def postAccount(request):
if is_ajax(request) and request.method == 'POST':
form = AccountForm (request.POST)
if form.is_valid():
instance = form.save()
ser_instance = serializers.serialize('json', [ser_instance,])
return JsonResponse({"instance":ser_instance}, status=200)
return JsonResponse ({"error":""}, status=400)
Disabled inputs won't appear in request.POST - you might have better luck using the readOnly attribute instead, it will do basically the same thing but will still include the value in request.POST

How do I JSON parse a Django queryset?

So I'm trying to parse each object in my Django queryset, and deal with the data through JavaScript. Below is my code (simplified) :
views.py (using Django Paginator, but the basic idea is the same.)
def main_page(request):
all_contents = Contents.objects.all()
paginator_contents = Paginator(contents,10)
page = request.GET.get('page')
all_contents_paginated = paginator_contents.get_page(page)
context = {
'contents' : contents,
'all_contents_paginated' : all_contents_paginated
}
return render(request, 'main/home.html', context)
template
{% for c in all_contents_paginated %}
<div class="text-m">
{{c.author}}
</div>
<div class="text-s" onclick="DetailModal('{{c}}')">
{{c.body}}
</div>
{% endfor %}
<script>
function DetailModal(c) {
}
</script>
Now obviously, the '{{c}}' cannot be parsed into JSON since it's string. I want to parse it into JSON in function DetailModal() and display the data in a separate modal element or do any other stuff with each data. But I can't figure out how to parse each object in the Django queryset.
Any ideas? Thanks.
you just modify your script to parse your item:
<script>
function DetailModal(c) {
const obj = JSON.parse(c);
console.log(obj.author);
console.log(obj.body);
}
</script>

Flask: Render jinja template with response from POST-request

I have an online store that uses local storage to keep track of which products are in the cart (stored like cart = [{"id":"1"},{"id":"2"},{"id":"4"}]). When the user navigates to cart.html, I want to send cart to my backend, generate a complete list of the products, and then use the list in a return render_template call.
The backend recieves the cart just fine and can generate the list without a problem, but I can't get the list to the cart.html page (it looks like if cart is empty). Should the POST request not be on cart.html and instead solve it with redirects? If so, how do I do that? I'd like to avoid having a "load cart" button on cart.html if possible.
This the beginning of cart.html (I've tried setting the ajax call to async: false, but it didn't stop the page from rendering without cart:
{% extends "layout.html" %}
{% block content %}
<script type="text/javascript">
function sendCart() {
$(document).ready(function() {
$.ajax({
url: "{{ url_for('cart', _external=True) }}",
type: 'POST',
data: JSON.stringify(JSON.parse(localStorage.getItem("cart"))),
contentType: "application/json; charset=utf-8",
dataType: "json",
});
})
}
sendCart();
</script>
...
And here is my route:
#app.route('/cart', methods=['GET', 'POST'])
#login_required
def cart():
cart = []
if request.method == 'POST':
for i in request.json:
cart.append(get_Furniture(int(i['id'])))
return render_template("cart.html", cart_objects = cart)
return render_template("cart.html", cart_objects = cart)
Edit: Solved
I found it easier to skip using ajax and localstorage, instead using a cookie that is easy to access in the backend: without the need for a request I can generate cart before rendering the page.
I found it easier to skip using ajax and localstorage, instead using a cookie that is easy to access in the backend: without the need for a request I can generate cart before rendering the page.

how to delete and objects from the db without refreshing the page?

I have a page that shows every objects in the database, this is handled by an ajax function that gets a JSON file containing every objects in the db and renders out some html code for every object.
There's also a classic Django ModelForm that allows the creations of new db's objects, the new objects is instantly loaded with the others.
I want an html button for every objects that deletes it "on the fly", so without redirecting to a Detail Delete template.
$('.remove').on('click', function() {
$.ajax({
type:'DELETE'
url: 'http://127.0.0.1:8000/MyApp/list-api/' + $(this).attr('data-id')
}
When the button is clicked it should send a DELETE request to the url of the detail api of the object. Nothing happens, no new request in the network tab of the browser.
This is my index.html
<body>
<h2>coffee orders</h2>
<ul id="orders">
</ul>
<h4>Add coffee order</h4>
<form method="POST" action=".">
{% csrf_token %}
{{form.as_p}}
<button id="add-order" type="submit">Add!!!</button>
</form>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="{% static 'MyApp/jquery_js.js' %}"></script>
</body>
This is my jquery.js,
this function get the api and renders out the infos about the object and a delete button which doens't work.
$(function (){
var $orders = $('#orders')
$.ajax({
type: 'GET',
url: 'http://127.0.0.1:8000/MyApp/list-api/?format=json',
success: function(orders) {
$.each(orders, function(i, order){
$orders.append('<li>name: '+order.name+', drink:
'+order.drink+'</li>')
$orders.append("<form method='DELETE'><button data-id=" +
(order.pk)+" class='remove'>X</button>")
});
},
error: function() {
alert('errore caricamento ordini');
}
});
def list_create_view(request):
form = DrinkModelForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
obj = form.save(commit=False)
obj.user = request.user
form.save()
form = DrinkModelForm()
context = {"form": form}
return render(request, "MyApp/index.html", context)
class OrderListView(generics.ListCreateAPIView):
pass
serializer_class = OrderSerializer
def get_queryset(self):
return Order.objects.all()
class OrderDetailView(generics.RetrieveDestroyAPIView):
pass
serializer_class = OrderSerializer
def get_object(self):
id_ = self.kwargs.get("pk")
return get_object_or_404(Order, pk=id_)
The X button should delete the objects from the db but nothings happens, I'm new to jquery so any help is really appreciated, thanks.
You should use the OrderDetailView for deletion and remove that pass from the class definition. BTW, you don't need to override the get_object method if you're passing the pk on the URL.
views.py
class OrderDetailView(generics.RetrieveDestroyAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer

How do I send an array of objects from a django class based view to my index.html file?

The Goal:
I want to use FullCalendar(https://fullcalendar.io/) to display event objects from my database. FullCalendar accepts an array of event objects as a property.
The Problem I'm having:
I can send context data back to the template with the event objects but as far as I know I can only interact with the data using Django's template tagging system. *EDIT: When I replace the hardcoded array with ptoHistory I receive the following error in the chrome console:
jquery-3.1.1.min.js:2 Uncaught ReferenceError: ptoHistory is not
defined
at HTMLDocument. ((index):141)
at j (jquery-3.1.1.min.js:2)
at k (jquery-3.1.1.min.js:2)
index.html:
{% extends 'base.html' %}
{% block content %}
//ACCESSING THE CONTEXT DATA LIKE THIS WORKS BUT I CAN'T USE ptoHistory IN MY FULLCALLENDAR SCRIPT
{% for history in ptoHistory %}
<li>{{obj.leave_type}}</li>
{% endfor %}
<div class="container">
<div id="calendar">
<!-- Calendar is injected here -->
</div>
<!----------------------- SCRIPTS ----------------------------->
<script>
$(document).ready(function() {
$('#calendar').fullCalendar({
defaultView:'month',
editable: true,
// MY ARRAY OF OBJECTS WILL REPLACE THIS HARDCODED ARRAY
events: [
{
title: 'All Day Event',
start: '2017-01-12',
},
{
title: 'Meeting',
start: '2017-01-13T10:30:26',
end: '2014-06-13T12:30:00'
},
],
});
});
</script>
{% endblock content%}
IndexView.py:
class IndexView(FormView):
template_name = 'accounts/index.html'
form_class = PtoRequestForm
success_url = 'login/'
def form_valid(self, form):
form.save()
return super(IndexView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['ptoHistory'] = PtoHistory.objects.all()
print(context['ptoHistory'])
return context
Could someone point me in the right direction?
You are right, it won't work. Django template system is able to process python objects because they are executed already before the template is finished rendering.
You could still assign python list in javascript, though, but not with python objects but json string. The solution is basically compose for only what you need in the views using values() then . I don't know what fields do you need for PtoHistory, but you could do:
# views.py
import json
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
ptoHistory = json.dumps(list(PtoHistory.objects.values()))
# or do this if you only need several fields' value
# ptoHistory = json.dumps(list(PtoHistory.objects.values('field1', 'field2')))
context['ptoHistory'] = ptoHistory
return context
// in javascript
$(document).ready(function() {
$('#calendar').fullCalendar({
defaultView:'month',
editable: true,
var histories = {{ ptoHistory|safe }};

Categories