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.
Related
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
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
My app's urls.py is:
from django.urls import path
from . import views
app_name = 'javascript'
urlpatterns = [
path('create_table', views.create_table, name='create_table')
My views.py is:
def create_table(request):
if request.method == 'POST':
row_data = "this is row data"
context = {'row_data': row_data}
return render(request, 'javascript/create_table.html',context)
My create_table.html is:
{% load static %}
<form action="" method="post">
{% csrf_token %}
<button id="create_table">Get data</button>
</form>
<div id="place_for_table"></div>
<script type="text/javascript">
var row_data = "{{ row_data }}"
</script>
<script src="{% static 'javascript/scripts/create_table.js' %}"></script>
And my create_table.js is:
function create_table() {
document.getElementById("place_for_table").innerHTML = row_data;
}
document.getElementById("create_table").onclick = function() {
create_table()
}
What I want to achieve is: when the /create table URL is requested, only the button is displayed. When the button is pressed, row_data variable's value is displayed below the button.
At this moment the data is displayed for a blink of an eye and then disappears.
I guess I am not distinguishing between POST and GET methods correctly in the view function. Also I have based my logic on the assumption that URL is requested using GET method by default. However if I put a print(request.method) at the beginning of my view, it prints POST.
Also, whenever I load the page for the first time or refresh it, I get a Firefox warning:"To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier."
Other things I tried was to use class-based view with post and get defs or put the create_table's URL in button formaction= tag, but that doesn't help.
I would be thankful for any suggestions on how to achieve this.
The problem might be because when you are submitting the form it refreshes/reloads your page i.e. /create_table url because of which row_data resets
This Might help you to understand why the button submits even though you didn't explicitly provided type="submit" to the button inside your form.
Our aim will be to prevent the event to occur. It can be done using a simple return false statement in our onclick listener as given below:
function create_table() {
document.getElementById("place_for_table").innerHTML = row_data;
}
document.getElementById("create_table").onclick = function(event) {
create_table();
return false;
}
I am using django and I have created an app in which I want to upload a zip file which is saved in a specific location (At this point my django server is localhost)
I have the following code which is working fine:
This is my HTML Template:
<form id="saveZipFile" enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<input type="file" name="docfile" id="docfile">
<input type="submit" id="upload-button" value="Upload">
</form>
This is my forms.py:
class UploadFileForm(forms.Form):
docfile = forms.FileField()
This is my views.py:
def handle_uploaded_file(f):
with open('uploaded_zip.zip', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['docfile'])
return HttpResponse()
else:
form = UploadFileForm()
return HttpResponse()
urls.py:
urlpatterns = [
url(r'^upload_file/$', views.upload_file, name='upload_file'),
]
But in the end, the url is changing to /upload_file - which is correct as I understand - and that page is empty (since I am returning an empty HttpResponse)
I am trying to build a Single-Page-Application and this redirection is throwing the entire state of my web-page out of the window.
Is there any way in which I can possible make an AJAX call instead of using django forms?
Thanks!
EDIT
I did add an ajax call that gets the uploaded file and sends it to the django view.
AJAX call:
var selectedFile = $('#docfile').files[0];
var fd = new FormData();
fd.append("file", selectedFile);
$.ajax({method: 'POST',
url: 'upload_file',
data: fd,
headers: {'Content-Type': undefined,
'X-CSRFToken': getCookie('csrftoken')
},
cache: false,
processData: false})
.done(function(data) {
alert(data)
});
But in the view when I print out request.POST, I get this mess (and many, many lines of it):
<QueryDict: {u'\x00\x00userapp/.git/objects/0e/34e20fc7131238973f102fe6d2d7fe102d12f4UT\x05\x00\x03\ufffd': [u'\xc0Yux\x0b\x00\x01\x04\xe8\x03\x00\x00\x04\xe8\x03\x00\x00PK\x01\x02\x1e\x03\n\x00\x00\x00\x00\x001\x852K\x00\x00\x00\x00\x00\x00\
You should use ajax for this, retrieve the data from the form, make the request and return false, which prevents the redirect from occurring. It should look this like this:
$(function() {
$('form').submit(function() {
$.ajax({
type: 'POST',
url: 'form-submit.php',
data: { name: $(this).name.value,
surname: $(this).surname.value }
});
return false;
});
})
How to call a view in my layout (template) ?
For example : I've a form on every pages of my website. I need to generate CSRF token for each pages but I don't want to put the generation code on every view.
Thank you.
In Django, once you reach the template, I don't believe you can call something to the effect of Zend's Action Helper.
Obviously, you could do an AJAX call to an exposed url in Django and retrieve the necessary data. In that case you can provide the csrf token to the ajax calls as follows..
$.ajaxSetup({data: {csrfmiddlewaretoken: '{{ csrf_token }}' },});
I'm not a hundred percent sure but you can implement something like Zend's Action Helper in a decorator (which could be applied to multiple views of your choice before processing the request) or in a context processor (which is applied to all views' processed request).
If your form is just HTML, then simply have a template containing the HTML and include that from other templates (or have it in your base template). To generate a CSRF token, you simply use {% csrf_token %} in the template, as explained at https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
If you want to generate the HTML of a Django form, then you could add a context processor - explained at https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext - that generates the form and then that will be available to all templates.
def form_processor(request):
form = Form()
return { 'form': form.as_p() }
Template:
<form>{% csrf_token %}{{ {{ form }}</form>