How to manage JSON data in javascript pass form django model? - javascript

I need to dynamically display my audio on my website. The audio is a file path stored in the Django model.
Djanog Model:
class audio(models.Model):
instrumentId = models.OneToOneField(instrument, on_delete=models.CASCADE, primary_key=True)
location = models.FileField()
I pass the data through view.py into json data so my script can read the data.
view.py, PostJsonListView fetch data form the model and generate json data, testView connect to the html displaying audios
class PostJsonListView(View):
def get(self, *args, **kwargs):
print(kwargs)
#upper is to get the number from the js file to set a upper boundry
upper = kwargs.get('num_aduios') #intial state be 3
lower = upper - 3
#pass in the audio in to the list [lower:upper] use to set boundry
audios = list(audio.objects.values()[lower:upper])
#comfirmation of no more audi to load
audio_size = len(audio.objects.values())
size = True if upper >= audio_size else False
return JsonResponse({'data':audios, 'max': size}, safe=False)
class testView(TemplateView):
template_name = 'frontend/testView.html'
JSON data in browser
Javascript that hand the data, after a button click, it would display three more data
console.log('HELLO')
const aduiosBox = document.getElementById('audio-box') //get the div audio-box
const nextBtn = document.getElementById('next-btn')
let visible = 3
const handleGetData = () =>{
$.ajax({
type: 'GET',
url: `/json/${visible}/`,
success: function(response)
{
max_size = response.max
//getting all the data and display in the console
const data = response.data
data.map(post=>{
console.log(post)
aduiosBox.innerHTML +=
//how to get the location right?
`
<div class="card p-3 mt-3 mb-3">
<audio controls>
<source src= ${post.location} type="audio/wav">
</audio>
</div>
`
})
//check if the display size reach maxium
if(max_size){
console.log('done')
}
},
error:function(error){
console.log(error)
}
})
}
handleGetData()
//event listenrs
nextBtn.addEventListener('click', ()=>{
visible += 3
handleGetData()
})
Console on the browser
Here, the audio path was from home/sound1.wav. From my another exmaple, where I also path audio object, has the path of /sounds/sounds1.wav
view.py for the working example
def survey(request):
if request.method == 'POST': #if something is post to the server, reference to HTML form method == post
form = rateForm(request.POST)
if form.is_valid():
form.save()
form = rateForm()
wavFile = audio.objects.all()
return render(request, "frontend/audio.html",{
'wavFile': wavFile,
'form': form,
})
Working example
File path of my Django app
In conclusion, I belive the website cannot get to the file path correctly. home/sound1.wav VS sounds/sound1.wav. How can I manage it so the Javascript code can get to the correct path to get the audio to display in the website?

I solved it by correcting the directory of my audio file. For anyone that is wondering the something, you should look at what have done to your setting.py for the directory of storing data you wanted to access

Related

Why does return jsonify() in flask goes to the API page instead of changing the page?

I am trying to make an upvote/downvote system on my Flask website, and I am trying to implement it using AJAX so the page won't reload every time there is an upvote or a downvote.
My flask application for project is:
#main.route('/project', methods=['GET', 'POST'])
def project():
...
return render_template('project.html', projects = all_projects, popular = liked_projects, recent = recent_projects,
users = all_users, comments = all_comments, followed = followed_projects, joined = joined_projects, my = my_projects, projectMember = projectMember)
My flask application for the upvote button is:
#main.route('/projects/upvote/<int:id>')
def projectupvote(id):
post = projectPosts.query.get_or_404(id)
post.likes += 1
db.session.commit()
return jsonify({"likes":post.likes})
My HTML is:
Up vote
Down vote
<h1 style="margin-bottom:5%; display: inline-block;" id = 'likes'> {{project.likes}}</h1>
And my JS application is:
$(document).ready(function() {
$('a').on('click', function(event) {
$.ajax({
data : {
likes : $('#likes').val(),
},
type : 'GET',
url : '/project'
})
.done(function(data) {
$('#likes').text(data.likes).show();
});
event.preventDefault();
});
});
When running the code, instead of updating the likes while staying on the page, it leads me to this:
It gives the correct data, but moves to another page displaying the raw JSON data of the likes.
Why does it happen and how to go about the situation? I have been researching for hours but couldn't get to the bottom of it.

Uploading Canvas (web camera snap) to Django Server

I need to take a snap on the client's side with JS [done in 1.] and send it to my server [trial in 2.].
By now, I can send images to the server (media/images/), using the auto-generated button from Django through forms/models and views, which allows a user to choose a pic from his own computer.
The thing here is that I don't want to rely on this process - that forces the user to select an image from his computer. Instead, I want that when the user takes a snap, the program sends it to the server automatically, and the server stores it in a folder.
I am new to Django, so I would really appreciate it if you could provide some code in your answers.
player1.html
<video id="video"></video>
<canvas id="canvas"></canvas><br>
<button onclick="snap();">Snap</button>
JS
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
navigator.mediaDevices.getUserMedia({video: true}) // request cam
.then(stream => {
video.srcObject = stream; // don't use createObjectURL(MediaStream)
return video.play(); // returns a Promise
})
function snap () {
canvas.width = video.clientWidth;
canvas.height = video.clientHeight;
context.drawImage(video, 0, 0); // This draws the captured image on the canvas
}
player1.html
<div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button id ='gg'>Upload</button>
</form>
</div>
JS
function snap () {
canvas.width = video.clientWidth;
canvas.height = video.clientHeight;
context.drawImage(video, 0, 0); // This draws the captured image on the canvas
console.log('canvas: ', canvas.toDataURL("image/jpeg"))
var formData = new FormData();
formData.append('csrfmiddlewaretoken', '{{ csrf_token }}');
formData.append("header_image", canvas.toDataURL("image/jpeg"));
var xhr = new XMLHttpRequest();
xhr.open( "POST", "http://127.0.0.1:8000/player1");
xhr.send(formData);
}
views.py
...
from encodings.base64_codec import base64_decode
class AddPostView(CreateView):
model = Post
form_class = PostForm
template_name = 'player1.html'
# fields = '__all__'
#def convert(self): I think I need something like this, but well written, to decode the image in here.. how should I write it, tho?
# print('here')
# base64_decode(self.object)
# print('hmm:', base64_decode(self.object))
urls.py
urlpatterns = [
path('', views.index, name='index'),
path('player1', AddPostView.as_view(), name='player1'),
]
models.py
class Post(models.Model):
header_image = models.ImageField(null=True, blank=True, upload_to="images/")
def get_absolute_url(self):
return reverse('player1')
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('header_image',) # these fields came from models.py
[Solution? B: LAST HOPE] - I also read from people with the same problem that they added the image on the database, using PHP, etc. So if I do that, how can I then grab it to manipulate it on views...?
If someone knows going on that way, all good by me!

AJAX way of handling filters in a Django based ecommerce application is not working upon copy pasting the url in new tab

So I ran into this problem two days back and still haven't got a proper solution. I would highly Appreciate any help in here.
Let me explain the scenario first, so the idea is I have one django based ecommerce site and I want to render the product showcase page through ajax call (without reloading) and same time also update the url as the selected filters for example (http://vps.vanijyam.com:8000/customerlist?category=category_1).
I want to achieve similar to this site - shutterstock.
My Scenario -
http://vps.vanijyam.com:8000/customerlist this page to showcase all the available products and also have the filters option and pagination.
Now when I change the page or apply some filter I am e.g. http://vps.vanijyam.com:8000/customerlist?category_slug=category_1 then it is working, but when I refresh the page it is not.. the reason behind this the way I am handling this ajax call in the backend.
def customer_categories(request):
# Get attributes from request url
current_page = request.GET.get('page' ,'1')
category_slug = request.GET.get('category_slug')
sortby_filter = request.GET.get('sortby_filter')
price_filter = request.GET.get('price_filter')
search_query= request.GET.get('term')
line_filter_min = request.GET.get('price_min')
line_filter_max = request.GET.get('price_max')
# Set limit and offset for queryset
limit = REQUEST_PER_PAGE * int(current_page)
offset = limit - REQUEST_PER_PAGE
categories = Category.objects.all()
# products = Product.objects.filter(available=True)[offset:limit] # limiting products based on current_page
# products_count = Product.objects.filter(available=True).count()
# Check product already in cartlist
cartlist_check = []
cart_item_count = cart_count(request)
cart_items = cart_list(request)
for cart in cart_items:
cartlist_check.append(cart['product'].id)
# Check product already in wishlist, only if user logged in
wishlist_check =[]
if request.user.is_authenticated:
wishlist_items_check = WishList.objects.filter(user=request.user)
for item in wishlist_items_check:
wishlist_check.append(item.product_id)
wishlist_count = wishlist_counts(request.user)
else:
wishlist_count = 0
# If category_slug True
if category_slug:
category = get_object_or_404(Category, slug=category_slug).\
get_descendants(include_self=True)
else:
category = None
time1 = time.time()
# Filters for multiselect, retun products and products_count
products, products_count, search_list = attribute_filter(category=category,
search_query=search_query,
sortby_filter=sortby_filter,
price_filter=price_filter,
line_filter_min=line_filter_min,
line_filter_max=line_filter_max,
offset=offset,
limit=limit)
time2= time.time()
print('Time Elapsed')
print(time2-time1)
if len(products) > 0:
# adding one more page if the last page will contains less products
total_pages = math.ceil(products_count / REQUEST_PER_PAGE )
cart_product_form = CartAddProductForm()
wish_list_form = WishListForm()
total_pages = math.ceil(products_count / REQUEST_PER_PAGE ) # adding one more page if the last page will contains less products
if not current_page == '1' or category_slug:
print('------------------------------')
return render(request, 'customer/products/products_by_category.html',\
{'products': products,
'wishlist_item_check': wishlist_check,
'cartlist_item_check': cartlist_check,
'current_page': current_page,
'total_products': products_count,
'request_per_page': REQUEST_PER_PAGE,
'total_pages':total_pages
})
else:
return render(request, 'customer/home/customer_showcase.html',\
{'products': products,
'categories':categories,
'cart_product_form': cart_product_form,
'wish_list_form': wish_list_form,
'wishlist_item_check': wishlist_check,
'wishlist_count': wishlist_count,
'cart':cart_items,
'items_count':cart_item_count,
'cartlist_item_check': cartlist_check,
'current_page': current_page,
'total_pages':total_pages,
'total_products': products_count,
'request_per_page': REQUEST_PER_PAGE,
})
Ajax part of the code is here
$('.selected_subcategory').on('click', function () {
send_data['selected_subcategory'] = $(this).attr('data-id');
getPopularProductsData($(this).attr('data-id'));
// getAPIData();
var params = window.location.search;
var path = window.location.pathname;
var old_url = path + params;
var url = old_url;
const state = {}
const title = ''
console.log('old urll', old_url)
let new_url=''
if(params){
new_url = removeDuplicate(old_url)
}
console.log('new url', new_url)
history.pushState(state, title, url)
$.ajax({
method: 'GET',
url: old_url,
data: {
category_slug: send_data['selected_subcategory']
},
beforeSend: function () {
$('#products').html('<div class="alert alert-success">Loading...</div>');
// $('#spinner3').addClass('d-block');
},
success: function (result) {
if (result['error']) {
let message =
'<div class="alert alert-danger">' +
result['error'] +
' <a class="" href="http://vps.vanijyam.com:8000/customerlist/" style="text-decoration: underline">click here</a>' +
'</div>';
$('#products').html(message);
} else {
document.getElementById('products').innerHTML = result;
}
const state = {}
const title = ''
const url = this.url
history.pushState(state, title, url)
},
error: function (response) {
$('html,body').animate({
scrollTop: 200,
});
$('#products').html(
'<div class="alert alert-danger">Something went wrong!!!</div>'
);
$('#list_data').hide();
// $('#spinner3').addClass('d-none');
},
});
});
My expectation is when I browse this http://vps.vanijyam.com:8000/customerlist?page=2&category_slug=category_1 link it would render the same which matches with the query params, but in a ajax way.
Sorry for the long explanation. Hope my point is clear through this explanation. Thanks in advance
Here in your Django part, you are returning two different HTML outputs when there is category_slug and not.
If there is category_slug in your request you returning 'customer/products/products_by_category.html'
But when there is no category slug you are returning 'customer/home/customer_showcase.html'.
Both HTML files are different in their layout. The first one doesn't provide the header or container elements. This is the central problem of your issue.
You can Fix this issue by
You can put a special parameter in ajax api call, by which Django can realize that is is an api call, this time it returns products_by_category.html.
And you want to make unique all other returns to customer_showcase.html, but if there is a category filter you can pass filtered content to the products list. If category_slug is None or empty you can pass all products without the filter to the same HTML file.
You can also differentiate ajax api call by making it a POST request and all other web requests remains GET requests. So you can easily identify the traffic.
Here is the changes in Django:
if request.method == "POST"::
print('------------------------------')
return render(request, 'customer/products/products_by_category.html',\
{'products': products,
'wishlist_item_check': wishlist_check,
'cartlist_item_check': cartlist_check,
'current_page': current_page,
'total_products': products_count,
'request_per_page': REQUEST_PER_PAGE,
'total_pages':total_pages
})
else:
return render(request, 'customer/home/customer_showcase.html',\
{'products': products,
'categories':categories,
'cart_product_form': cart_product_form,
'wish_list_form': wish_list_form,
'wishlist_item_check': wishlist_check,
'wishlist_count': wishlist_count,
'cart':cart_items,
'items_count':cart_item_count,
'cartlist_item_check': cartlist_check,
'current_page': current_page,
'total_pages':total_pages,
'total_products': products_count,
'request_per_page': REQUEST_PER_PAGE,
})
And make your ajax call to "POST", change in your front end code: method: 'POST',
Don't forget to add slash(/) at the end of url when you change to POST.

Django 3. Having trouble passing dropdown menu selection from .html to forms

I'm still new to Django (2 weeks or so). I've been struggling the past few days with passing a string from an html file to forms. My project lets the user choose a state from a dropdown menu (Michigan and Ohio for now, I'll add the rest later). When the state is selected, it will take that string and pull a list of counties of that state from a spreadsheet. This is where the problem lies. I've searched far and wide and I just can't seem to find a solution. The major holdback to many of these solutions is I don't want to "submit" with a button. I want the user to "select" a state, then select a county without a page refresh. I've also included a screenshot of the webpage. So far the dependent dropdowns work perfectly thanks to a youtube tutorial. The "submit" button in the picture is cosmetic for now.
Thanks in advance for helping out. Let me know if you have any questions regarding models or anything else regarding the code.
views.py
def StateForm_Page(request):
context = {}
stateChoice = 'Michigan' //hardcode a state so if the post fails, the function can still find an excel sheet
if request.method == 'POST':
State_Form = StateForm(request.POST)
stateChoice = State_Form.cleaned_data['stateChoice'] //I think this is where my code is failing
else:
State_Form = StateForm()
context['State_Form'] = State_Form
dataArray = pd.read_excel(r'C:\filename.xls', sheet_name= stateChoice)
county_strings = dataArray['County '].values.tolist()
json_county_strings = json.dumps(county_strings)
context['json_county_strings'] = json_county_strings
return render(request, 'StateForm_page.html', context)
StateForm_page.html
<body>
<form action="" method="POST" name="stateChoice">
{% csrf_token %}
{{ State_Form.as_p }}
</form>
<script>
var state;
var county;
$(document).ready(function(){
$('#id_county').empty(); //empties county before state is chosen
$("#id_state").on('change', function(){ //when #id_state is changed...
state = $("#id_state").val(); //assign state with the selection
var countyStrings = JSON.parse('{{ json_county_strings | escapejs }}'); //grabs counties from respective state
var length = countyStrings.length;
var i;
for(i=0; i < length; i++){
county = countyStrings[i]; //update county options with spreadsheet values
$('#id_county').append(
`
<option value ="${county}">
${county}
</option>
`
);
}
});
})
}
</script>
</body>
What the webpage looks like so far:
Next day changes
Hey, after putting a few more hours into it, I'm still not having every luck. Per your suggestions, below is what I've added
views.py
def retrieveState(request):
statePick = request.GET.get('state')
return JsonResponse(statePick, safe = False)
def StateForm_Page(request):
context = {}
stateChoice = []
if request.method == 'POST':
#stateChoice = State_Form.cleaned_data['stateChoice']
State_Form = StateForm(request.POST)
stateChoice = retrieveState(request)
else:
stateChoice = 'Michigan'
State_Form = StateForm()
StateForm_Page.html
$.ajax({
type: 'POST',
url: 'ajax/retrieveState/',
data: state,
dataType: 'json',
});
Good news is something is being triggered on the ajax url I added, but I don't think the function in views is retrieving the ajax data. Any suggestions? Thanks for your help!

Data update without page reload jinja2

The data has to be refreshed without page reload. Originally data is appeared on html with jinja2.
#app.route('/personal_account', methods=['POST'])
def welcome():
login = request.form['login']
data = get_default_user_data(login)
# ... processing
return render_sidebar_template("personal_account.html", data=data)
According to these data graph is building with chartist.js.
personal_account.html
<div id="data">
<ul id="consumed_values">
{% set count = 0 %}
{% for i in data.consumed_values %}
<li>{{ data.consumed_values[count] }}</li>
{% set count = count + 1 %}
{% endfor %}
</ul>
</div>
<canvas width="800" height="600" id="canvas"></canvas>
<button id="button">Update</button>
I need to update data. I am using ajax.
The function "request" make a post request to the server to the function get_selected_values in Python.
This function gives new data. But new data doesn't display in jinja2 on page. The data is still old.
personal_account.js
window.onload = draw();
function draw() {
var consumed_values = document.querySelectorAll('ul#consumed_values li');
var values = new Array();
for (var i = 0; i < consumed_values.length; i++) {
console.log(consumed_values[i].innerHTML);
values[i] = consumed_values[i].innerHTML;
}
var numbers = new Array();
for(var i=0; i<consumed_values.length; i++)
{
numbers[i]=i+1;
console.log(numbers[i]);
}
var ctx = document.getElementById('canvas').getContext('2d');
var grapf = {
labels : numbers,
datasets : [
{
strokeColor : "#6181B4",
data : values
}
]
}
new Chart(ctx).Line(grapf);
}
document.getElementById('button').onclick=function () {
request();
}
function reques() {
var first = selected[0];
var second = selected[1];
first.month = first.month+1;
second.month = second.month+1;
$.ajax({
type: 'POST',
url: '/get_selected_values',
success: function(response) {
alert('Ok');
draw();
},
error: function() {
alert('Error');
}
});
}
Function get_selected_values()
#app.route('/get_selected_values', methods=['POST'])
def get_selected_values():
# ...
data = fetch_selected_date(start_date=start_date, end_date=end_date, login=current_user.get_id())
if data:
# return jsonify({'result': True, 'data': data}) # does not work this way
# return jsonify({'result': False, 'data': []})
return render_sidebar_template("personal_account.html", data=data, result=1)
How to succeed in data's update and graph's rebuild?
EDIT 1
I am using the first version of get_selected_values function.
The request function look like this:
...
success: function(response) {
alert('Успешно получен ответ:!'+ response.data);
document.getElementById('consumed_values').innerHTML = response.data;
draw();
},
...
Data is updating successfully, but graph looks the same. How to fix?
OK here's my outlook on this. You're on the right track and there is a way to update the element without the need to re-draw the page in this instance. What's happening is that you are returning data from your get_selected_values() method but not doing anything with it once it's returned to your AJAX request.
So firstly, I'm going to draw your attention to your AJAX request:
$.ajax({
type: 'POST',
url: '/get_selected_values',
success: function(response) {
alert('Ok');
draw();
},
error: function() {
alert('Error');
}
});
When you're getting a successful response from this, you're seeing your "OK" alert in the UI, right? However nothing updates in the UI despite you calling on the draw() method?
You won't want to return a render_template from your Flask function in this case. You were already on the right track with returning JSON from your function:
if data:
# return jsonify({'result': True, 'data': data}) # does not work this way
When you return your JSON data, it will be stored in the response variable in your success function. If you're unsure of exactly what's going into that response variable then output its contents with something like alert(JSON.stringify(response)) in the success function of your AJAX request. From here you will see your data returned to your method.
Now you need to decide how you want to use that data to update your <div id="data"> element in your UI. You can do this just using JavaScript with a series of document.getElementById('element_id').innerHTML statements or such-like so that your element is populated with all of the updated data from your response.
This will auto-update the data you wish to have displayed without the need to refresh the page.
Now that you've done that, invoke your draw() function again and it should now use the updated data.
I hope this helps set you down the right path with this one!
AFTER EDIT 1
When you're originally populating <div id="data"> you are using a loop to populate a series of <li> tags in the element with your data.
When you are updating this element with your new data, you are just using .innerHTML to re-populate the parent <ul> element.
Your draw() method is looking to the data stored in the <li> elements.
Are you absolutely certain that, after you perform your update, your <div id="data"> element is in exactly the same (ie. expected) format to work with your draw() method? In that it's still in the structure:
<div id="data">
<ul id="consumed_values">
<li>Your updated data here...</li>
<li>More updated data...</li>
</ul>
</div>
This is the element structure that your draw() method is expecting to find. It's pulling its data in from each individual <li> element in the list. So these are the elements which need to store your updated values.

Categories