如何在 Django 2 中实现 Django-Private-Chat
Posted
技术标签:
【中文标题】如何在 Django 2 中实现 Django-Private-Chat【英文标题】:how to implement Django-Private-Chat in Django 2 【发布时间】:2019-06-26 03:19:46 【问题描述】:我正在做一个项目,我需要为用户实现私人聊天,因此一个用户可以与另一个用户私下交流,为此我使用django-private-chat,但我对如何实现感到困惑这在我的应用程序中?
这是我到目前为止所做的:
1): 安装websockets
2): 安装django-private-chat
3):添加到INSTALLED_APPS
4):然后在main中添加urls.py
like:
来自project.urls.py
:
path('', include('jobexpertapp.urls')),
url(r'', include('django_private_chat.urls')),
来自myapp.urls.py
:
re_path(r'^users/$', views.UserListView.as_view(), name='user_list'),
5):为此添加一个视图:
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):然后添加两个模板:(a):users.html
(b):dialogs.html
来自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 %
来自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 %
【问题讨论】:
【参考方案1】:你让它太复杂了,你不需要写任何视图或任何东西。在你使用pip install django-private-chat
安装django-private-chat
并将其添加到已安装的应用程序之后。
将以下行添加到您的设置 .py 文件中
CHAT_WS_SERVER_HOST = 'localhost'
CHAT_WS_SERVER_PORT = 5002
CHAT_WS_SERVER_PROTOCOL = 'ws'
接下来你需要做的是将它的所有 url 指向你的主项目的 urls.py。 它应该看起来像这样,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')),
]
下一步是前端部分,希望你有一个项目的静态目录,如果没有在与项目的 manage.py 文件相同的路径中创建一个静态文件夹。
现在从环境中复制 django-private-chat 的静态文件夹的内容。它的路径是 your_venv_name/lib/pythonX.X/site-packages/django_private_chat/static
。将此静态文件夹的所有内容复制到项目的静态文件夹中。它应该看起来像这样 your_project/static/django_private_chat/static
接下来是您的 dailog.html 页面。如果您的项目中还没有创建模板文件夹,请创建一个。然后在该模板文件夹中创建一个“base.html”文件,base.html 文件的内容如下所示: base.html
<html><head></head><body>
% block content %
% endblock %
%block js%
%endblock%
% block extra_js %% endblock extra_js %
</body>
接下来在您的模板文件夹中,创建 dailogs.html 文件,复制您在问题中在 dailogs.html 中编写的任何内容,只需将其复制到 %block css%
中即可
block.super
<link href="% static 'django_private_chat/css/django_private_chat.css' %" rel="stylesheet" type="text/css" media="all">
现在在一个终端窗口runserver
和另一个终端窗口中,与运行服务器的目录相同。执行
python manage.py run_chat_server
转到浏览器并登录到您的 django 项目。然后转到 http://127.0.0.1:8000/dialogs/
您会找到与之聊天的用户。
【讨论】:
我已按照这些步骤操作,但无法正常工作。我在控制台中看到了这个错误。File "/Users/raakesh/Python/venvironment/lib/python3.7/site-packages/websockets/compatibility.py", line 8 asyncio_ensure_future = asyncio.async # Python < 3.5
已修复。这是 Python 版本的问题。我使用的是 3.7,因此我不得不将 websockets 库更新为 7.0 而不是 od 3.2,这是该聊天库所必需的
@RaakeshKumar 如果对您有帮助,请为答案投票
为什么要导入:from django_private_chat import urls as django_private_chat_urls
?因为你不使用django_private_chat_urls
。
你是怎么解决这个问题的?我无法让它工作以上是关于如何在 Django 2 中实现 Django-Private-Chat的主要内容,如果未能解决你的问题,请参考以下文章