I run with success a flask application interfaced with a MySQL database, all running fine.
I'm now trying to build a Dashboard page that will build charts and updates them as the data evolves.
Those charts will be filled-up with dedicated queries defined in the routes and pushed to the proper HTML template with jQuery/Ajax.
I'm stuck at the point where it seems no data gets out of my #home.route > data() function and i can't figure out why. The error in the debuger tells me that the data is "undefined" (the value data is of float type, containg "." decimals).
My .js knowledge being ridiculously low, i'd appreciate if somebody could help me progress on my error.
Thank you very much.
This is my main route.
#home.route('/admin/dashboard', methods=['GET','POST'])
def data():
conn = None
cursor = None
try:
conn = mysql.connect()
cursor = conn.cursor()
sql = "SELECT location_id, SUM(workload) FROM collaborators GROUP BY location_id ORDER BY DATE(location_id) DESC";
cursor.execute(sql)
rows = cursor.fetchall()
data = []
for row in rows:
data.append({'location_id': str(row[0]), 'workload': float(row[1])})
return jsonify({'payload': json.dumps({'workload':data,'location_id':labels})})
This is my HTML also sheltering the chart script.
<!-- app/templates/home/admin_dashboard.html -->
{% extends "base.html" %}
{% block title %}Admin Dashboard{% endblock %}
{% block body %}
<div class="intro-header">
<div class="container" style="height:50px">
<p>Dynamic chart using .JS, Ajax & jQuery</p>
</div>
<canvas id="myChart" width="100" height="70"></canvas>
<script>
$(document).ready(function(){
var _data;
var _labels;
$.ajax({
url: "/admin/dashboard",
type: "get",
dataType:"json",
data:{vals: ''},
success: function(response) {
console.log("This is the returned data: " + JSON.stringify(response));
full_data = JSON.parse(response.payload);
console.log(full_data);
_data = full_data['workload'];
_labels = full_data['location_id'];
},
error: function(error){
console.log("Here is the error res: " + JSON.stringify(error));
}
});
// define the chart data
var chartData = {
labels : _labels,
datasets : [{
label: 'workload',
fill: false,
borderColor: 'rgba(255, 25, 255, 1.0)',
data: _data,
},
]
}
// get chart canvas
var ctx = document.getElementById("myChart").getContext("2d");
// create the chart using the chart canvas
var myChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
legend: { display: true },
title: {
display: false,
text: 'Predicted world population (millions) in 2050'
}
}
});
});
</script>
</div>
{% endblock %}
And finally, this is my base.HTML.
<!-- app/templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ title }} - Proc. Headcount</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/xcharts.min.css') }}"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js "></script>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="{{ url_for('static', filename='js/charts/d3.js') }}"></script>
<script src="{{ url_for('static', filename='js/charts/sugar.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/charts/xcharts.min.js') }}"></script>
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top topnav" style="background-color: #0c0d29;background-color:#000000;" role="navigation">
<div class="container topnav">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<div class="logo" >
<a href="{{ url_for('home.homepage') }}">
<img src="{{STATIC_URL}}../../../static/img/Thales_Logo2.png">
</a>
</div>
<ul class="nav navbar-nav navbar-right">
{% if current_user.is_authenticated %}
{% if current_user.is_admin %}
<li><a class="outward" href="{{ url_for('home.data') }}">Dashboard</a></li>
<li><a class="outward" href="{{ url_for('admin.list_functions') }}">Functions</a></li>
<li><a class="outward" href="{{ url_for('admin.list_roles') }}">Roles</a></li>
<li><a class="outward" href="{{ url_for('admin.list_locations') }}">Locations</a></li>
<li><a class="outward" href="{{ url_for('admin.list_collaborator') }}">Collaborators</a></li>
{% else %}
<li>Dashboard</li>
{% endif %}
<li><a class="outward" href="{{ url_for('auth.logout') }}">Logout</a></li>
<li><a><i class="fa fa-user"></i> Hi, {{ current_user.username }}!</a></li>
{% else %}
<li>Home</li>
<li>Register</li>
<li>Login</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="wrapper">
{% block body %}
{% endblock %}
<div class="push"></div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="col-lg-12">
<ul class="list-inline">
<li>Home</li>
<li class="footer-menu-divider">⋅</li>
<li>Register</li>
<li class="footer-menu-divider">⋅</li>
<li>Login</li>
</ul>
<p class="copyright text-muted small">Thales / Procurement</p>
</div>
</div>
</div>
</footer>
</body>
</html>
for row in rows:
data.append({'location_id': str(row[0]), 'workload': float(row[1])})
I would try printing what you are returning (the jsonify) to see if that's correct, and then if it's not then I would go back to the above line and see if this is how you should be appending to an array of json objects. Will the jsonify accept that?
Okay i solved my problem I think.
Thanks to this : Accessing python list in javascript as an array
The problem was that i was not materializing the interface between my HTML template (hosting the javascript) and my Flask function executing the SQL.
I abandoned flask.jsonify / dumps method, to directly implement the value/labels names in the render_template(). I still have some improvements to do though.
Also i modified my script client-side to use {{ data|tojson|safe }}.
#home.route('/admin/dashboard', methods=['GET','POST'])
#login_required
def admin_dashboard():
# prevent non-admins from accessing the page
if not current_user.is_admin:
abort(403)
conn = None
cursor = None
try:
conn = mysql.connect()
cursor = conn.cursor()
sql = "SELECT location_id, SUM(workload) as workload FROM collaborators GROUP BY location_id;"
cursor.execute(sql)
rows = cursor.fetchall()
test = []
labels = []
for index in range(len(rows)):
test.append(rows[index][1])
labels.append(float(rows[index][0]))
return render_template('home/admin_dashboard.html', title="Dashboard", test = test, labels = labels)
except Exception as e:
print(e)
finally:
if cursor and conn:
cursor.close()
conn.close()
<script>
$(document).ready(function(){
var data = JSON.parse('{{test | tojson | safe}}');
var labels = JSON.parse('{{labels | tojson | safe}}');
console.log(labels)
$.ajax({
url: "/admin/dashboard",
type: "get",
contentType: "application/json; charset=utf-8",
dataType:"json",
data:{vals:''},
success: function(response) {
console.log(response);
full_data = JSON.parse('{{test | tojson | safe}}');
console.log(full_data);
data = full_data['data'];
labels = full_data['labels'];
},
});
// define the chart data
var chartData = {
labels: labels,
datasets : [{
label: 'workload',
fill: true,
borderColor: 'rgba(25, 25, 25, 1)',
backgroundColor:'steelblue',
data: data
}],
}
// get chart canvas
var ctx = document.getElementById("myChart").getContext("2d");
// create the chart using the chart canvas
var myChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
legend: { display: true },
title: {
display: true,
text: 'Procurement Headcount'
}
}
});
});
</script>
Related
I am trying to get the specific pk of the selected object when the user accepts a delivery. My problem is that I'm getting only the first object's pk in the list every time. I want to get the pk of the selected object.
views:
#login_required(login_url="/signin/?next=/driver/")
def deliveries_available_page(request):
deliveries = Delivery.objects.filter(
status_of_delivery__in=[Delivery.DELIVERY_POSTED]
)
#When driver accept delivery then status of delivery changes to delivering
if request.method == 'POST':
delivery = get_object_or_404(Delivery, pk=request.POST.get('receipt_number'))
if delivery:
delivery.status_of_delivery = Delivery.DELIVERY_DELIVERING
delivery.driver = request.user.driver
messages.success(request, 'Delivery Accepted')
delivery.save()
return redirect(reverse('driver:deliveries_available'))
return render(request, 'driver/deliveries_available.html', {
"GOOGLE_API_MAP": settings.GOOGLE_API_MAP,
"del": deliveries
})
HTML:
<div class="d-flex flex-column h-100" style="padding-bottom: 50px">
<div id="map"></div>
{% if del %}
{% for d in del %}
<div class="card" id="delivery-popup">
<div class="card-body p-2">
<div class="details">
<div class="p-2">
<strong id="address"></strong>
<div>
<strong id="show-info"></strong>
</div>
<div>
<strong id="show-distance"></strong>
<strong id="show-duration"></strong>
</div>
<div>
<strong id="show-price"></strong>
<strong id="show-id"></strong>
</div>
<div>
<form method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-primary" name="accept">Accept</button>
<input type="hidden" value="{{ d.receipt_number }}" name="receipt_number">
</form>
</div>
{% if messages %}
{% for m in messages %}
{% if m.tags %}
<script>alert("{{ m }}")</script>
{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
I need the specific pk so when user accept delivery, then the right delivery is accepted and removed from the map. Any help would be appreciated. Thanks.
I can get the specific pk by creating new url and passing it in the url but i want user to accept delivery on the map page.
script added to html
<script>
//Google map and using api to display deliveries on map and click event to show delivery details
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 53.350140, lng: -6.266155 },
zoom: 13,
});
fetch("{% url 'driver:available_deliveries' %}").then(response => response.json()).then(json => {
console.log(json);
for (let d = 0; d < json.deliveries.length; d++) {
const delivery = json.deliveries[d];
const position = { lat: delivery.delivery_address_latitude, lng: delivery.delivery_address_longitude };
const show_on_map = new google.maps.Marker
({
position,
map,
});
new google.maps.InfoWindow({
content: "<small><strong>" + delivery.address + "<medium><br>€" + delivery.price
}).open(map, show_on_map);
show_on_map.addListener("click", () => {
PopUpDelivery(delivery);
})
}
})
}
function PopUpDelivery(delivery) {
$("#delivery-popup").css("display", "block");
$("#address").html(delivery.address);
$("#show-distance").html(delivery.distance + " Km");
$("#show-duration").html(delivery.duration + " Mins");
$("#show-price").html("€ " + delivery.price);
$("#show-info").html("Info : " + delivery.information);
$("#show-id").html("Pk : " + delivery.receipt_number)
}
Keep id unique in html document
The id in an HTML document must be unique within each page source:
The id global attribute defines an identifier (ID) which must be
unique in the whole document. Its purpose is to identify the element
when linking (using a fragment identifier), scripting, or styling
(with CSS).
What I think may have occurred is that since you have many cards in each page, all with the same id's, you were just getting the first one. While your solution works, I think it might be better to give each id a unique value, which you can do simply by appending the receipt_number, or any unique field to the id names. With this, you may not need the function getTag. Here is what I mean:
html
<div class="d-flex flex-column h-100" style="padding-bottom: 50px">
<div id="map"></div>
{% if del %}
{% for d in del %}
<div class="card" id="delivery-popup{{ d.receipt_number }}">
<div class="card-body p-2">
<div class="details">
<div class="p-2">
<strong id="address{{ d.receipt_number }}"></strong>
<div>
<strong id="show-info{{ d.receipt_number }}"></strong>
</div>
<div>
<strong id="show-distance{{ d.receipt_number }}"></strong>
<strong id="show-duration{{ d.receipt_number }}"></strong>
</div>
<div>
<strong id="show-price{{ d.receipt_number }}"></strong>
<strong id="show-id{{ d.receipt_number }}"></strong>
</div>
<div>
<form method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-primary" name="accept">Accept</button>
<input type="hidden" value="{{ d.receipt_number }}" name="receipt_number">
</form>
</div>
{% if messages %}
{% for m in messages %}
{% if m.tags %}
<script>alert("{{ m }}")</script>
{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
script
<script>
//Google map and using api to display deliveries on map and click event to show delivery details
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 53.350140, lng: -6.266155 },
zoom: 13,
});
fetch("{% url 'driver:available_deliveries' %}").then(response => response.json()).then(json => {
console.log(json);
for (let d = 0; d < json.deliveries.length; d++) {
const delivery = json.deliveries[d];
const position = { lat: delivery.delivery_address_latitude, lng: delivery.delivery_address_longitude };
const show_on_map = new google.maps.Marker
({
position,
map,
});
new google.maps.InfoWindow({
content: "<small><strong>" + delivery.address + "<medium><br>€" + delivery.price
}).open(map, show_on_map);
show_on_map.addListener("click", () => {
PopUpDelivery(delivery);
})
}
})
}
function PopUpDelivery(delivery) {
let pk = delivery.receipt_number
$("#delivery-popup"+pk).css("display", "block");
$("#address"+pk).html(delivery.address);
$("#show-distance"+pk).html(delivery.distance + " Km");
$("#show-duration"+pk).html(delivery.duration + " Mins");
$("#show-price"+pk).html("€ " + delivery.price);
$("#show-info"+pk).html("Info : " + delivery.information);
$("#show-id"+pk).html("Pk : " + delivery.receipt_number)
}
Solved:
Got the specific pk, when i click on a delivery it gets the right pk, code below if anyone has the same problem:
script
function PopUpDelivery(delivery) {
$("#delivery-popup").css("display", "block");
$("#address").html(delivery.address);
$("#show-distance").html(delivery.distance + " Km");
$("#show-duration").html(delivery.duration + " Mins");
$("#show-price").html("€ " + delivery.price);
$("#show-info").html("Info : " + delivery.information);
$("#show-id").html("Pk : " + delivery.receipt_number);
var input_tag = getTag('getpk');
input_tag.value = delivery.receipt_number;
}
function getTag(id){
return document.getElementById(id);
}
html
<button type="submit" class="btn btn-primary" name="accept">Accept</button>
<input type="hidden" id="getpk" value="" name="receipt_number">
I'm trying to build a website that generates a power hour style video from a list of music videos that the user selects by searching through the youtube api. I'm having trouble figuring out how to append selected videos to a list (addedVideos) in view.py from a button (add) in my html. I need to append each added video to a list so I can display them and loop through them in an embedded youtube player. This is my first django project so I don't have a good understanding of what the potential problems could be. index.html and views.py below:
views.py
import requests
from isodate import parse_duration
from django.conf import settings
from django.shortcuts import render, redirect
def index(request):
addedVideos = []
videos = []
if request.method == 'POST':
search_url = 'https://www.googleapis.com/youtube/v3/search'
video_url = 'https://www.googleapis.com/youtube/v3/videos'
search_params = {
'part' : 'snippet',
'q' : request.POST['search'],
'key' : settings.YOUTUBE_DATA_API_KEY,
'maxResults' : 3,
'type' : 'video'
}
#print(request.POST['submit'])
r = requests.get(search_url, params=search_params)
#print(r)
results = r.json()['items']
#print(results)
video_ids = []
for result in results:
video_ids.append(result['id']['videoId'])
if request.POST['submit'] == 'lucky':
return redirect(f'https://www.youtube.com/watch?v={ video_ids[0] }')
video_params = {
'key' : settings.YOUTUBE_DATA_API_KEY,
'part' : 'snippet,contentDetails',
'id' : ','.join(video_ids),
'maxResults' : 3
}
r = requests.get(video_url, params=video_params)
results = r.json()['items']
for result in results:
video_data = {
'title' : result['snippet']['title'],
'id' : result['id'],
'url' : f'https://www.youtube.com/watch?v={ result["id"] }',
'duration' : int(parse_duration(result['contentDetails']['duration']).total_seconds() // 60),
'thumbnail' : result['snippet']['thumbnails']['high']['url']
}
videos.append(video_data)
if request.POST['add'] == 'addValue':
print("add clicked")
context = {
'videos' : videos,
'addedVideos': addedVideos
}
return render(request, 'search/index.html', context)
index.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Search YouTube</title>
<!-- Bootstrap core CSS -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="{% static 'search/album.css' %}" rel="stylesheet">
</head>
<body>
<main role="main">
<section class="jumbotron text-center">
<div class="container">
<h1 class="jumbotron-heading">Build Your Power Hour</h1>
<p class="lead text-muted">Select music videos to add to your power hour</p>
<form method="POST">
<div class="input-group mb-3">
{% csrf_token %}
<input type="text" name="search" class="form-control" aria-label="Username">
</div>
<p>
<button type="submit" name="submit" value="search" class="btn btn-primary my-2">YouTube Search</button>
<button type="submit" name="submit" value="lucky" class="btn btn-secondary my-2">I'm Feeling Lucky</button>
</p>
</form>
</div>
</section>
<div class="album py-5 bg-light">
<div class="container">
<div class="row">
{% for video in videos %}
<div class="col-md-4">
<div class="card mb-4 shadow-sm">
<img class="bd-placeholder-img card-img-top" width="100%" height="225" src="{{ video.thumbnail }}" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" aria-label="Placeholder: Thumbnail"></img>
<div class="card-body">
<p class="card-text">{{ video.title }}</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<form method="POST">
{% csrf_token %}
<button type="submit" name="add" value="addValue" id='{{ video }}' class="btn btn-sm btn-outline-secondary">Add</button>
</form>
</div>
<small class="text-muted">{{ video.duration }} mins</small>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</main>
</body>
</html>
Running this as is gives a MultiValueDictKeyError at 'q' : request.POST['search'],
Any help would be appreciated, thanks.
You should put / in front of search/index.html instead of search/index.html.
And you don't have to have the https:// you can just put // instead.
I've some trouble with decode base64 image in my django project.
I am passing the image to views like this (I've some form. I'm passing image to function from views.py through this form):
{% extends "blog/base.html" %}
{% block content %}
<div id="content" class="container-fluid d-flex h-100 justify-content-center align-items-center p-0">
<div class="row bg-white shadow-sm">
<div class="col border rounded p-4">
<h3 class="text-center mb-4">Диагноз</h3>
<form action="" id="post-form">
<div class="form-group">
<p align="center" style="font-weight:bold"><label for="exampleFormControlFile1">Снимок</label></p>
<input type="file" class="form-control-file" id="image-selector">
</div>
</form>
<p align="center" style="font-weight:bold">Predictions</p>
<p>Covid: <span id="covid-prediction"></span></p>
<p>Health: <span id="health-prediction"></span></p>
<table align="center">
<tr>
<td>
<img id="selected-image" class="img-thumbnail" width="300px" height="300px" src=""/>
</td>
</tr>
<tr align="center">
<td>
<button id="predict-button" type="submit" class="btn btn-primary">Predict</button>
</td>
</tr>
</table>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script>
let base64Image;
$("#image-selector").change(function() {
let reader = new FileReader();
reader.onload = function(e) {
let dataURL = reader.result;
$("#selected-image").attr("src", dataURL);
base64Image = dataURL.replace("data:image/jpeg;base64,","");
console.log(base64Image);
}
reader.readAsDataURL($("#image-selector")[0].files[0]);
$("#covid-prediction").text("");
$("#health-prediction").text("");
});
$("#predict-button").click(function(event){
let message = base64Image;
console.log(message);
$.post("{% url "diagnose:submit_prediction" %}", message, function(response){
$("#covid-prediction").text(response.prediction.covid.toFixed(3) * 100 + "%");
$("#health-prediction").text(response.prediction.health.toFixed(3) * 100 + "%");
console.log(response);
});
});
</script>
And in my views file I'm trying to decode this image like this:
#csrf_exempt
def predict_chances(request):
myDict = request.POST.dict()
encoded = 0
for k in myDict:
encoded = k
print(encoded)
im = Image.open(io.BytesIO(base64.b64decode(encoded)))
processed_image = preprocess_image(image, target_size=(224, 224))
prediction = model.predict(processed_image).tolist()
response = {
'prediction': {
'covid': prediction[0][0],
'health': prediction[0][1]
}
}
return jsonify(response)
But this is not working. I get this error:
binascii.Error: Incorrect padding
How I can fix this?
I'm working on a project in which I need to implement private chat for user, so one user can communicate with another user privately, for that purpose I'm using django-private-chat but I'm confused in how to implement this in my application?
Here's what I have done so far:
1): Install websockets
2): Install django-private-chat
3): Add it in INSTALLED_APPS
4): Then add in main urls.py like:
From project.urls.py:
path('', include('jobexpertapp.urls')),
url(r'', include('django_private_chat.urls')),
From myapp.urls.py:
re_path(r'^users/$', views.UserListView.as_view(), name='user_list'),
5): Add a view for that:
class UserListView(LoginRequiredMixin, generic.ListView):
model = get_user_model()
# These next two lines tell the view to index lookups by username
slug_field = 'username'
slug_url_kwarg = 'username'
template_name = 'jobexpertapp/users.html'
login_url = '/login'
6): Then add two templates: (a): users.html (b): dialogs.html
From users.html:
{% extends "base.html" %}
{% block content %}
<h3>Here you can see users avaliable for chat, excluding yourself (chat with yourself is possible thought):</h3>
<div class="container">
{% for user in object_list %}
{% if user != request.user %}
<p>{{ user.get_full_name }}</p>
<a href="{% url 'dialogs_detail' user.username %}" class="btn btn-primary">
Chat with {{ user.username }}
</a>
{% endif %}
{% endfor %}
</div>
{% endblock %}
From dialogs.html:
{# This template is here just to demonstrate how to customize the default one. #}
{# It has none to very few changes #}
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block css %}
{% endblock css %}
{% block content %}
<input id="owner_username" type="hidden" value="{{ request.user.username }}">
<div class="container">
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans "Chat list" %}</h3>
</div>
<div class="panel-body">
<div class="user-list-div">
<ul style="list-style-type: none;">
{% for dialog in object_list %}
<li>
{% if dialog.owner == request.user %}
{% with dialog.opponent.username as username %}
<a href="{% url 'dialogs_detail' username %}" id="user-{{ username }}"
class="btn btn-danger">{% trans "Chat with" %} {{ username }}</a>
{% endwith %}
{% else %}
{% with dialog.owner.username as username %}
<a href="{% url 'dialogs_detail' username %}" id="user-{{ username }}"
class="btn btn-danger">{% trans "Chat with" %} {{ username }}</a>
{% endwith %}
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-9">
<div class="well well-lg">
<div class="row">
<div class="col-md-3 col-md-offset-9">
<span class="pull-right" hidden id="typing-text">
<strong>{{ opponent_username }} {% trans "is typing..." %}</strong>
</span>
</div>
<p>
{{ opponent_username }}
</p>
<p class="text-success" id="online-status" style="display: none">{% trans "Online" %}</p>
<p class="text-danger" id="offline-status" style="display: none">{% trans "Offline" %}</p>
<div class="messages-container">
<div id="messages" class="messages">
{% for msg in active_dialog.messages.all %}
<div class="row {% if msg.read %}msg-read{% else %}msg-unread{% endif %} {% if msg.sender != request.user %}opponent{% endif %}"
data-id="{{ msg.id }}">
<p class="{% if msg.sender == request.user %}pull-left{% else %}pull-right{% endif %}">
<span class="username">{{ msg.sender.username }}:</span>
{{ msg.text }}
<span class="timestamp">– <span
data-livestamp="{{ msg.get_formatted_create_datetime }}">{{ msg.get_formatted_create_datetime }}</span></span>
</p>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="row">
<div class="add-message">
<div class="form-group">
<textarea id="chat-message" class="form-control message"
placeholder="{% trans 'Write a message' %}"></textarea>
</div>
<div class="form-group clearfix">
<input id="btn-send-message" type="submit" class="btn btn-primary pull-right send-message"
style="margin-left: 10px;" value="{% trans 'Send' %}"/>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/scrollmonitor/1.2.0/scrollMonitor.js"
integrity="sha256-BseZlDlA+yL4qu+Voi82iFa5aaifralQEXIjOjaXgeo=" crossorigin="anonymous"></script>
<script>
var base_ws_server_path = "{{ ws_server_path }}";
$(document).ready(function () {
var websocket = null;
var monitor = null;
function initReadMessageHandler(containerMonitor, elem) {
var id = $(elem).data('id');
var elementWatcher = containerMonitor.create(elem);
elementWatcher.enterViewport(function () {
var opponent_username = getOpponnentUsername();
var packet = JSON.stringify({
type: 'read_message',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
message_id: id
});
$(elem).removeClass('msg-unread').addClass('msg-read');
websocket.send(packet);
});
}
function initScrollMonitor() {
var containerElement = $("#messages");
var containerMonitor = scrollMonitor.createContainer(containerElement);
$('.msg-unread').each(function (i, elem) {
if ($(elem).hasClass('opponent')){
initReadMessageHandler(containerMonitor, elem);
}
});
return containerMonitor
}
function getOpponnentUsername() {
return "{{ opponent_username }}";
}
// TODO: Use for adding new dialog
function addNewUser(packet) {
$('#user-list').html('');
packet.value.forEach(function (userInfo) {
if (userInfo.username == getUsername()) return;
var tmpl = Handlebars.compile($('#user-list-item-template').html());
$('#user-list').append(tmpl(userInfo))
});
}
function addNewMessage(packet) {
var msg_class = "";
if (packet['sender_name'] == $("#owner_username").val()) {
msg_class = "pull-left";
} else {
msg_class = "pull-right";
}
var msgElem =
$('<div class="row msg-unread" data-id="' + packet.message_id + '">' +
'<p class="' + msg_class + '">' +
'<span class="username">' + packet['sender_name'] + ': </span>' +
packet['message'] +
' <span class="timestamp">– <span data-livestamp="' + packet['created'] + '"> ' + packet['created'] + '</span></span> ' +
'</p> ' +
'</div>');
$('#messages').append(msgElem);
scrollToLastMessage()
}
function scrollToLastMessage() {
var $msgs = $('#messages');
$msgs.animate({"scrollTop": $msgs.prop('scrollHeight')})
}
function generateMessage(context) {
var tmpl = Handlebars.compile($('#chat-message-template').html());
return tmpl({msg: context})
}
function setUserOnlineOffline(username, online) {
var elem = $("#user-" + username);
if (online) {
elem.attr("class", "btn btn-success");
} else {
elem.attr("class", "btn btn-danger");
}
}
function gone_online() {
$("#offline-status").hide();
$("#online-status").show();
}
function gone_offline() {
$("#online-status").hide();
$("#offline-status").show();
}
function flash_user_button(username) {
var btn = $("#user-" + username);
btn.fadeTo(700, 0.1, function () {
$(this).fadeTo(800, 1.0);
});
}
function setupChatWebSocket() {
var opponent_username = getOpponnentUsername();
websocket = new WebSocket(base_ws_server_path + '{{ request.session.session_key }}/' + opponent_username);
websocket.onopen = function (event) {
var opponent_username = getOpponnentUsername();
var onOnlineCheckPacket = JSON.stringify({
type: "check-online",
session_key: '{{ request.session.session_key }}',
username: opponent_username
{# Sending username because the user needs to know if his opponent is online #}
});
var onConnectPacket = JSON.stringify({
type: "online",
session_key: '{{ request.session.session_key }}'
});
console.log('connected, sending:', onConnectPacket);
websocket.send(onConnectPacket);
console.log('checking online opponents with:', onOnlineCheckPacket);
websocket.send(onOnlineCheckPacket);
monitor = initScrollMonitor();
};
window.onbeforeunload = function () {
var onClosePacket = JSON.stringify({
type: "offline",
session_key: '{{ request.session.session_key }}',
username: opponent_username,
{# Sending username because to let opponnent know that the user went offline #}
});
console.log('unloading, sending:', onClosePacket);
websocket.send(onClosePacket);
websocket.close();
};
websocket.onmessage = function (event) {
var packet;
try {
packet = JSON.parse(event.data);
console.log(packet)
} catch (e) {
console.log(e);
}
switch (packet.type) {
case "new-dialog":
// TODO: add new dialog to dialog_list
break;
case "user-not-found":
// TODO: dispay some kind of an error that the user is not found
break;
case "gone-online":
if (packet.usernames.indexOf(opponent_username) != -1) {
gone_online();
} else {
gone_offline();
}
for (var i = 0; i < packet.usernames.length; ++i) {
setUserOnlineOffline(packet.usernames[i], true);
}
break;
case "gone-offline":
if (packet.username == opponent_username) {
gone_offline();
}
setUserOnlineOffline(packet.username, false);
break;
case "new-message":
var username = packet['sender_name'];
if (username == opponent_username || username == $("#owner_username").val()){
addNewMessage(packet);
if (username == opponent_username) {
initReadMessageHandler(monitor, $("div[data-id='" + packet['message_id'] + "']"));
}
} else {
if ($("#user-"+username).length == 0){
var new_button = $(''+
'<a href="/'+ username + '"' +
'id="user-'+username+'" class="btn btn-danger">{% trans "Chat with" %} '+username+'</a>');
$("#user-list-div").find("ul").append()
}
flash_user_button(username);
}
break;
case "opponent-typing":
var typing_elem = $('#typing-text');
if (!typing_elem.is(":visible")) {
typing_elem.fadeIn(500);
} else {
typing_elem.stop(true);
typing_elem.fadeIn(0);
}
typing_elem.fadeOut(3000);
break;
case "opponent-read-message":
if (packet['username'] == opponent_username) {
$("div[data-id='" + packet['message_id'] + "']").removeClass('msg-unread').addClass('msg-read');
}
break;
default:
console.log('error: ', event)
}
}
}
function sendMessage(message) {
var opponent_username = getOpponnentUsername();
var newMessagePacket = JSON.stringify({
type: 'new-message',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
message: message
});
websocket.send(newMessagePacket)
}
$('#chat-message').keypress(function (e) {
if (e.which == 13 && this.value) {
sendMessage(this.value);
this.value = "";
return false
} else {
var opponent_username = getOpponnentUsername();
var packet = JSON.stringify({
type: 'is-typing',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
typing: true
});
websocket.send(packet);
}
});
$('#btn-send-message').click(function (e) {
var $chatInput = $('#chat-message');
var msg = $chatInput.val();
if (!msg) return;
sendMessage($chatInput.val());
$chatInput.val('')
});
setupChatWebSocket();
scrollToLastMessage();
});
</script>
{% endblock %}
You are making it too complex,you don't need to write any view or anything.After You have installed django-private-chat using pip install django-private-chat and added it to installed apps.
Add following lines to your settings .py file
CHAT_WS_SERVER_HOST = 'localhost'
CHAT_WS_SERVER_PORT = 5002
CHAT_WS_SERVER_PROTOCOL = 'ws'
Next thing you need to do is all its url to your main project's urls.py.
It should look something like this , URLS.py
from django_private_chat import urls as django_private_chat_urls
urlpatterns = [
#other urls of ur project
path('', include('django_private_chat.urls')),
]
Next step is front-end part,hope u have an static directory of your project,if not create an static folder in path same as of your manage.py file of your project.
Now copy contents of static folder of django-private-chat from enviroment.It's path would be your_venv_name/lib/pythonX.X/site-packages/django_private_chat/static.Copy all the contents of this static folder to your project's static folder.It should look somehing like this your_project/static/django_private_chat/static
Next thing is your dailog.html page. If you don't have templates folder in your project already created,create one.Then In that templates folder make an 'base.html' file, contents of your base.html file would be something like this:
base.html
<html><head></head><body>
{% block content %}
{% endblock %}
{%block js%}
{%endblock%}
{% block extra_js %}{% endblock extra_js %}
</body>
Next in your templates folder,create dailogs.html file,an copy whatever you have written in dailogs.html in your question,just copy this inside the {%block css%}
{{ block.super }}
<link href="{% static 'django_private_chat/css/django_private_chat.css' %}" rel="stylesheet" type="text/css" media="all">
Now in One terminal window runserver and in another terminal windows from same directory of where your runserver is running. Execute
python manage.py run_chat_server
go to browser and login into your django project.then go to http://127.0.0.1:8000/dialogs/
you'll find the users to chat with.
I've been stuck on this issue for a few weeks as I'm not very familiar with how to get the ajax set up. I'm working on a Django app which is basically one page that has a Dropdown menu. I would like to get whatever the user selects from the Dropdown menu and pass that data into my views.py so I can use that information to display a graph. Right now the graph part is working (I can pass in hard coded data into it and it will generate the graph) and my dropdown is working as well. However, I don't know how to get data from the drop down into my views.py. Here is how it looks.
Display.html
{% extends "RecordEvent/nav.html" %}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
</head>
{% block content %}
<div class="row">
<div class="padded">
<div class="download-header">
<h3>Logs</h3>
<div class="row inline download-header">
<div class="col-lg-6">
<div class="dropdown padding col-lg-6">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span id="dropdownTitle" class="">Measurable</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% include 'RecordEvent/includes/EntryDropdown.html' %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class='padded'>
<div class='col-sm-12' url-endpoint='{% url "api-data" %}'>
<h1>Graph Data</h1>
<canvas id="myChart" width="400" height="400"></canvas>
</div>
</div>
<script>
{% block jquery %}
var endpoint = 'display/api/chart/data/'
var defaultData = []
var defaultLabels = [];
$.ajax({
method: "GET",
url: endpoint,
success: function(data){
defaultLabels = data.labels
defaultData = data.default
console.log(data)
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: defaultLabels,
datasets: [{
label: '# Measurable',
data: defaultData,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
{% endblock %}
</script>
{% endblock %}
The first div creates the Dropdown menu. Everything below is to get the graph setup.
views.py
#login_required
def DisplayView(request):
return render(request,'DisplayData/Display.html')
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
all_entries = models.Entries.objects.all().filter(parent=2) #change to input from drop down
all_id = models.Entries.objects.all().values_list('id', flat=True)
all_measurables = models.Measurables.objects.all().filter(user_id=1) #change to current user
all_times = [m.timestamp for m in all_entries]
all_data = []
for m in all_entries:
data = m.data
json_data = json.loads(data)
value = json_data['value']
all_data.append(value)
data = {
"labels": all_times,
"default": all_data,
#"default": all_parent,
}
return Response(data)
#login_required
def LogDisplay(request):
measurables=[entry for entry in models.Measurables.objects.all().filter(user_id=request.user.id)]
return render(request, 'DisplayData/Logs.html',{'dropdown':measurables})
I need to get the value from the drop down into the where the comment says get value from drop down.
How can I do it?
to post via form
<form method='post' action = 'api url'>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% include 'RecordEvent/includes/EntryDropdown.html' %}
</ul>
</form>
amd in views.py access with
request.post[<name>]
to post via ajax
$('ul li').click(function(){
$.ajax({
url: <api url>,
type:'post',
data:{<name>:$(this).html()},
})