[英]Django - How to display user's profile picture with a message after its sent?
I have a live chat application and I'm trying to display a profile picture with the message after its sent with Javascript.我有一个实时聊天应用程序,我试图在使用 Javascript 发送消息后显示带有消息的个人资料图片。 Here is my code...
这是我的代码...
Models.py - here is my Message and Profile model Models.py - 这是我的消息和个人资料模型
class Message(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.CharField(max_length = 255)
content = models.TextField()
date_added = models.DateTimeField(auto_now_add = True)
class Meta:
ordering = ('date_added', )
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
Consumers.py消费者.py
class ChatRoomConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = 'chat_%s' % self.room_name
print(self.room_group_name)
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
username = text_data_json['username']
room = text_data_json['room']
await self.save_message(username, room, message)
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chatroom_message',
'message': message,
'username': username,
}
)
async def chatroom_message(self, event):
message = event['message']
username = event['username']
await self.send(text_data=json.dumps({
'message': message,
'username': username,
}))
@sync_to_async
def save_message(self, username, room, message):
user = User.objects.get(username = username)
Message.objects.create(author = user, room = room, content = message)
pass
And here is the Javascript code for the live chat...这是实时聊天的Javascript代码...
{{ request.user.username|json_script:"user_username" }}
{{ room_name|json_script:"room-name" }}
<script>
const user_username = JSON.parse(document.getElementById('user_username').textContent);
document.querySelector('#submit').onclick = function (e) {
const messageInputDom = document.querySelector('#input');
const message = messageInputDom.value;
if(message.trim() == ''){
}
else {
chatSocket.send(JSON.stringify({
'message': message,
'username': user_username,
'room': roomName,
}));
messageInputDom.value = '';
}
};
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const chatSocket = new WebSocket(
'ws://' +
window.location.host +
'/ws/chat/' +
roomName +
'/'
);
chatSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
console.log(data)
if (data.message) {
document.querySelector('#chat-text').innerHTML += ('<img id="imageid" src="{{ message.author.profile.image.url }}">' + data.username + '<br>' + data.message + '<br>');
}
else {
}
}
</script>
The problem is with this <img id="imageid" src="{{ message.author.profile.image.url }}">
in the Javascript code.问题在于Javascript代码中的
<img id="imageid" src="{{ message.author.profile.image.url }}">
。 So my question is, how can I display the user's profile picture with the message after its sent without refreshing the page?所以我的问题是,如何在不刷新页面的情况下在消息发送后显示用户的个人资料图片?
您可以使用 Ajax 仅刷新网页的一部分,使用不同的 HTML 文档,其中包含用于显示个人资料图片的 Django HTML。
You don't need to use AJAX here, you are communicating with the server via WebSockets, you can get the data you need through it.这里不需要使用AJAX,你是通过WebSockets与服务器通信,通过它就可以得到你需要的数据。
Looks like you are using django-channels.看起来您正在使用 django-channels。 Check django-channels documentation about authentication .
检查有关身份验证的django-channels 文档。 If you enable it, you will be able to access the current user through
self.scope['user']
.如果启用它,您将能够通过
self.scope['user']
访问当前用户。
So, you will able to do something like this:因此,您将能够执行以下操作:
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
username = self.scope['user'].username
profile_pic = self.scope['user'].profile.image.url # None handling required
room = text_data_json['room']
await self.save_message(username, room, message)
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chatroom_message',
'message': message,
'username': username,
'profile_pic': profile_pic
}
)
async def chatroom_message(self, event):
message = event['message']
username = event['username']
profile_pic = event['profile_pic']
await self.send(text_data=json.dumps({
'message': message,
'username': username,
'profile_pic': profile_pic
}))
# on the frontend
chatSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
console.log(data)
if (data.message) {
document.querySelector('#chat-text').innerHTML += (`<img id="imageid" src="${data.profile_pic}">` + data.username + '<br>' + data.message + '<br>');
}
else {
}
Note that you can't make database calls from async context because database connector works in a synchronous manner.请注意,您不能从异步上下文进行数据库调用,因为数据库连接器以同步方式工作。 When you are getting a profile pic
self.scope['user'].profile.image.url
you are actually making a DB call to get user's profile.当您获得个人资料图片
self.scope['user'].profile.image.url
您实际上是在进行数据库调用以获取用户的个人资料。
What you need to do in such cases is make a db call using either database_sync_to_async
or sync_to_async
decorators.在这种情况下,您需要做的是使用
database_sync_to_async
或sync_to_async
装饰器进行database_sync_to_async
调用。
For example:例如:
from channels.db import database_sync_to_async
@database_sync_to_async
def get_user_profile(self):
return self.scope['user'].profile
# and in receive method you call it
async def receive(self, text_data):
profile = await self.get_user_profile()
profile_pic = profile.image.url
....
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.