Django-Private-Chat in , TemplateDoesNotExist at /dialogs/ - python

This is the code of my base.html
{% comment %}
As the developer of this package, don't place anything here if you can help it
since this allows developers to have interoperability between your template
structure and their own.
Example: Developer melding the 2SoD pattern to fit inside with another pattern::
{% extends "base.html" %}
{% load static %}
<!-- Their site uses old school block layout -->
{% block extra_js %}
<!-- Your package using 2SoD block layout -->
{% block javascript %}
<script src="{% static 'js/ninja.js' %}" type="text/javascript"></script>
{% endblock javascript %}
{% endblock extra_js %}{% endcomment %}
This is code of dialogs.html
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block css %}
{{ block.super }}
<link href="{% static 'django_private_chat/css/django_private_chat.css' %}" rel="stylesheet" type="text/css" media="all">
{% endblock css %}
{% block content %}
<input id="owner_username" type="hidden" value="{{ request.user.username }}">
<div class="container">
<div class="col-md-3">
<div class="user-list-div">
<ul>
{% 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 class="col-md-9">
<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 %}"
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>
{% endblock %}
{% block extra_js %}
{{ block.super }}
<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
});
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,
});
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":
if (packet['sender_name'] == opponent_username || packet['sender_name'] == $("#owner_username").val()) {
addNewMessage(packet);
if (packet['sender_name'] == opponent_username) {
initReadMessageHandler(monitor, $("div[data-id='" + packet['message_id'] + "']"));
}
} else {
flash_user_button(packet['sender_name']);
}
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 should copy both 'dialogs.html' and 'base.html' from:
\your_virtualenvs\your_project\Lib\site-packages\django_private_chat\templates\django_private_chat\
into:
\your_project\templates\django_private_chat\
in order to modify them accordingly.
And add this to your settings if you din't already:
TEMPLATES = [
{
...
'DIRS': [ os.path.join( BASE_DIR, 'templates' ) ],
...
}
]
Reference:
https://django-private-chat.readthedocs.io/en/latest/readme.html#example-project

Related

Django - Can't get the specific primary key (id) for an object in a list of objects

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">

How do i update comment count using Ajax

i am working on a project in Django where users can comment on a post. How do i update the comment count of each post, when user comment on a post increases the count to 1. I tried adding the id to div's but nothing happened. How do i implement this?
Home Template:
<!-- Comment count post is an object of all post in homepage -->
<div class="col-4 col-md-4 col-lg-4" id="newfeeds-form">
<a href="{% url 'site:comments' post.id %}" class="home-comment-icon z-depth-0">
<img src="{{ '/static/' }}images/comment.png" width="19" height="19" alt="comment-icon">
{% if post.comments.all|length > 999 %}
<span class="font-weight-bold dark-grey-text" id="number-of-comments">
{{ post.comments.count|floatformat }}
</span>
{% else %}
<span class="font-weight-bold dark-grey-text" id="number-of-comments">
{{ post.comments.count }} Comment{{ post.comments.count|pluralize }}
</span>
{% endif %}
</a>
</div>
<!-- New Feeds Comment Form -->
<div id="newfeeds-form">
{% include 'ajax_newfeeds_comments.html' %}
</div>
Ajax submit comment:
$(document).ready(function() {
$('.feeds-form').on('submit', onSubmitFeedsForm);
$('.feeds-form .textinput').on({
'keyup': onKeyUpTextInput,
'change': onKeyUpTextInput // if another jquery code changes the value of the input
});
function onKeyUpTextInput(event) {
var textInput = $(event.target);
textInput.parent().find('.submit').attr('disabled', textInput.val() == '');
}
function onSubmitFeedsForm(event) {
event.preventDefault();
// if you need to use elements more than once try to keep it in variables
var form = $(event.target);
var textInput = form.find('.textinput');
var hiddenField = form.find('input[name="post_comment"]');
$.ajax({
type: 'POST',
url: "{% url 'site:home' %}",
// use the variable of the "form" here
data: form.serialize(),
dataType: 'json',
beforeSend: function() {
// beforeSend will be executed before the request is sent
form.find('.submit').attr('disabled', true);
},
success: function(response) {
// as a hint: since you get a json formatted response you should better us "response.form" instead of response['form']
$('#newfeeds-form' + hiddenField.val()).html(response.form);
// do you really want to reset all textarea on the whole page? $('textarea').val('');
textInput.val(''); // this will trigger the "change" event automatically
},
error: function(rs, e) {
console.log(rs.resopnseText);
},
complete: function() {
// this will be executed after "success" and "error"
// depending on what you want to do, you can use this in the "error" function instead of here
// because the "success" function will trigger the "change" event automatically
textInput.trigger('change');
}
});
}
});
If you are sure that a new comment will be created with each request, than you can do it with incrementing the count on your desired html element.
I have not worked with python or django so far, but have tried to optimize the code.
<!-- ... -->
<div class="col-4 col-md-4 col-lg-4" id="newfeeds-form">
<span class="font-weight-bold dark-grey-text" id="number-of-comments" data-number="{{ post.comments.count }}">
{% if post.comments.count > 999 %}
{{ post.comments.count|div:1000|floatformat:1 }}k Comments
{% else %}
{{ post.comments.count }} Comment{{ post.comments.count|pluralize }}
{% endif %}
</span>
</div>
<!-- ... -->
function onSubmitFeedsForm(event) {
// ...
$.ajax({
// ...
success: function(response) {
$('#newfeeds-form' + hiddenField.val()).html(response.form);
textInput.val('');
// how you can increment the value of the amount of comments
refreshNumberOfComments();
},
// ...
});
// ...
}
// ...
function refreshNumberOfComments() {
var numberOfCommentsElement = $('#number-of-comments');
var numberOfComments = parseInt(numberOfCommentsElement.data('number')) + 1;
numberOfCommentsElement.data('number', numberOfComments);
if (numberOfComments == 1) {
numberOfCommentsElement.text(numberOfComments + ' Comment');
} else if (numberOfComments > 999) {
numberOfCommentsElement.text((numberOfComments / 1000).toFixed(1) + 'k Comments');
} else {
numberOfCommentsElement.text(numberOfComments + ' Comments');
}
}
Another option is to give the request the information about the amount of comments.
So you could make it in jQuery like this example
$.ajax({
// ...
success: function(response) {]
$('#newfeeds-form' + hiddenField.val()).html(response.form);
textInput.val('');
// your server side script should implement a new field "number_of_comments"
refreshNumberOfComments(response.number_of_comments); // for this call the function above has to get a parameter
},
// ...
});

how to implement Django-Private-Chat in Django 2

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.

django render template variables and tags via ajax

I want to use Django+jquery-ajax to refresh my blog's new comments.
The code is as follows:
views.py:
#require_POST
def wirte_comment(request):
"""ajax new article comment"""
if request.user.is_anonymous:
login_url = reverse('login')
return JsonResponse({'status': 'redirect',
'login_url': login_url})
# logined
article_id = int(request.POST.get('article_id'))
comment_form = ArticleCommentForm(request.POST)
article = get_object_or_404(Article, id=article_id)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.author = request.user
new_comment.article = article
new_comment.save()
create_action(request.user, article,
verb=f"{request.user.username} commentted《{article.title}》")
# comment html
with open('blog/templates/blog/add_comment.html') as f:
html = f.read()
return JsonResponse({'status': 'ok',
'html': html})
else:
return JsonResponse({'status': 'ko'})
I sent the HTML of the new comment as a string to the front end:
add_comment.html:
<div class="comment">
<p class="comment-author">
<a href="{% url 'account:user_detail' article.author %}">
{% avatar article.author 25 class="circle-avatar" %}
</a>
<a href="{% url 'account:user_detail' article.author %}">
{{ article.author }}
</a>
{{ comment.created |date:'y/m/d h:i' }}
</p>
<p>{{ comment }}</p>
</div>
article.html
<script>
$(document).ready(function () {
$('#new_comment').click(function () {
var text = $('#text').val();
$.post(comment_url,
{
article_id: article_id,
content: text
},
function (data) {
if (data['status'] === 'redirect') {
window.location.href = data['login_url'];
}
if (data['status'] === 'ok') {
$('#comment-list').prepend(data['html']);
}
}
);
});
});
</script>
And then there's a problem:
When I submit a new comment,it's rendered like this:
{% avatar article.author 25 class="circle-avatar" %} {{ article.author }} {{ comment.created |date:'y/m/d h:i' }}
{{ comment }}
How can i solve this problem?
Thanks very much.
I think you need to wrap your logic inside the success function of the ajax call.
$(document).ready(function () {
$('#new_comment').click(function () {
var text = $('#text').val();
$.ajax({
url:comment_url,
data : {
article_id: article_id,
content: text
},
dataType: 'json',
success: function (data){
if (data['status'] === 'redirect') {
window.location.href = data['login_url'];
}
if (data['status'] === 'ok') {
$('#comment-list').prepend(data['html']);
}
}
})
})
});

Django Ajax and Looping over Response

I currently have the following template,
{% extends "123/123-base.html" %}
{% block main %}
<script type="text/javascript">
$(document).ready(function() {
$("#button").click(function() {
var host = $("#hostinput").val();
var record = $("#recordinput").val();
$.ajax({
url : "/lookup_ajax",
type : "POST",
dataType: "json",
data : {
hostinput : host,
recordinput : record,
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success : function(json) {
$('#mainsection').append( "response" + json.response );
},
error : function(xhr,errmsg,err) {
alert(xhr.status + ": " + xhr.responseText);
}
});
return false;
});
});
</script>
<div id="mainsection">
<div id="maininput" class="input-append">
<form method="post" name="inputlookup" action="/lookup_ajax">
{% csrf_token %}
<input class="span2" id="hostinput" name="hostinput" type="text">
<select title="Record" id="recordinput" name="recordinput" >
<option value="A">A</option>
<option value="MX">MX</option>
<option value="Cname">Cname</option>
</select>
<button id="button" class="btn" type="submit">Lookup</button>
</form>
</div>
<div id="mainouput">
</div>
</div>
{% endblock %}
However the response I receieve back from the server I want to loop over using the Django template tags, like this,
{% extends "123/123-base.html" %}
{% block main %}
{% if error %}
{{ error }}
{% else %}
<ul>
<table class="table table-style table-striped">
<thead>
<tr>
<th>HOSTNAME</th>
<th>TTL</th>
<th>CLASS</th>
<th>TYPE</th>
<th>DETAILS</th>
</tr>
</thead>
{% for answer in response %}
<tr>
{% for field in answer %}
<td>{{ field }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</ul>
{% endif %}
{% endblock %}
Any ideas on how this should be done ?
Thanks,
It looks to me like you're returning a JSON object for your AJAX call. If that's correct then django doesn't come into it for displaying the result. You'd need to change your success function to something like the following:
success: function(json){
// Table header
var table = $('<table>').addClass('table table-style table-striped');
var thead = $('<thead>');
var headrow = $('<tr>');
var head1 = $('<th>').text('HOSTNAME');
var head2 = $('<th>').text('TTL');
var head3 = $('<th>').text('CLASS');
var head4 = $('<th>').text('TYPE');
var head5 = $('<th>').text('DETAILS');
$(headrow).append(head1, head2, head3, head4, head5);
$(thead).append(headrow);
$(table).append(thead);
// table body
var tbody = $('<tbody>');
num_answers = json.length
for (i = 0; i < num_answers; i++) {
var row = $('<tr>');
var cell1 = $('<td>').text(json[i][0]);
var cell2 = $('<td>').text(json[i][1]);
var cell3 = $('<td>').text(json[i][2]);
var cell4 = $('<td>').text(json[i][3]);
var cell5 = $('<td>').text(json[i][4]);
$(row).append(cell1, cell2, cell3, cell4, cell5);
$(tbody).append(row);
}
$(table).append(row);
$('#mainsection').append(table);
}

Categories