Функциональность обмена сообщениями в Django не работает
Итак, я пытаюсь добавить функцию обмена сообщениями на свой сайт электронной коммерции, где покупатели могут отправлять сообщения продавцам, а продавцы могут отправлять сообщения покупателям, когда покупатель что-то у них купил (я еще не написал код для этого, просто хочу, чтобы базовая функциональность обмена сообщениями была убрана с дороги). Вот что я пробовал.
Теперь есть три проблемы с этим. Первая заключается в том, что когда я нахожусь в файле user_message.html, если я ввожу сообщение и нажимаю кнопку "Отправить", я получаю ошибку:
Page not found (404) No Business matches the given query.
Когда очевидно, что у меня есть url для этого.
Во-вторых, когда я отправляю сообщение через представление message_seller
, создается экземпляр сообщения, это работает, но получатель не получает сообщение на своей странице user_messages_view, что как бы лишает его цели.
В-третьих, я пытался заставить счетчики работать, но оба счетчика не работают. Счетчик unread_message_counter
должен показывать количество непрочитанных сообщений от разных предприятий/пользователей, а счетчик individual_business_message_counter
должен показывать количество непрочитанных сообщений от конкретного предприятия. Когда я нажимаю на сообщение, чтобы перейти к детальному просмотру беседы, именно тогда сообщения должны быть is_read = True
.
Три проблемы, может ли кто-нибудь помочь мне решить их? Заранее спасибо!
Мой models.py:
class Business(models.Model):
BUSINESS_TYPE_CHOICES = [
('product', 'Product Business'),
('service', 'Service Business'),
]
seller = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name='business')
business_name = models.CharField(max_length=100)
description = models.TextField()
business_slug = models.SlugField(unique=True, blank=True)
business_type = models.CharField(max_length=20, choices=BUSINESS_TYPE_CHOICES)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
address = models.CharField(max_length=200)
phone = models.CharField(max_length=20)
website = models.URLField(blank=True, null=True)
email = models.EmailField(blank=True, null=True)
profile_picture = models.ImageField(upload_to='business_profiles/', blank=True, null=True)
banner_image = models.ImageField(upload_to='business_banners/', blank=True, null=True)
is_featured = models.BooleanField(default=False)
def __str__(self):
return self.business_name
def save(self, *args, **kwargs):
if not self.business_slug:
self.business_slug = slugify(self.business_name)
super().save(*args, **kwargs)
class Message(models.Model):
sender = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='sent_messages')
recipient = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='received_messages')
business = models.ForeignKey(Business, on_delete=models.CASCADE, related_name='messages', null=True)
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
is_read = models.BooleanField(default=False)
def __str__(self):
return f"Message from {self.sender.username} to {self.recipient.username}"
Мой views.py:
Мой urls.py:
urlpatterns = [
path('', views.home, name="home"),
path('message/<slug:business_slug>/', views.message_seller, name='message_seller'),
path('messages/', views.user_messages_view, name='user_messages'),
path('messages/?business_slug=<slug:business_slug>', views.user_messages_view, name='user_messages'),
]
Мое сообщение.html:
Мой user_messages.html:
когда пользователь пишет владельцу бизнеса, владелец бизнеса не получает сообщение.
Я имею в виду, что сообщение не отображается в папке входящих сообщений получателя.
Ваш запрос касается только сообщений, отправленных бизнесу и полученных от него, а не сообщений, полученных для бизнеса. В вопросе не определено, как должны отображаться такие чаты с каждым отправителем, поскольку в вопросе сообщения чата сгруппированы по бизнесам.
Тем не менее, в этом ответе будет показано, как запрашивать и отображать сообщения для бизнеса с другими пользователями. Аналогичным образом вам нужно будет обработать if request.user == business.seller
для случая, когда "владельцы бизнеса могут сообщить покупателю" в if request.method == 'POST'
, который не показан в этом ответе.
1.a. Запросите user_messages
для бизнеса у других пользователей, передайте 'user'
в шаблон:
def user_messages_view(request):
businesses = Business.objects.filter(
Q(messages__sender=request.user) | Q(messages__recipient=request.user)
).distinct()
user_messages = []
for business in businesses:
if request.user == business.seller:
# Query user_messages for business with other users
messages = Message.objects.filter(
Q(sender=business.seller) |
Q(recipient=business.seller)
).filter(business=business).order_by('-timestamp')
for user, chat in itertools.groupby(messages, lambda m: m.recipient if m.sender == request.user else m.sender):
last_message = next(chat)
user_messages.append({
'business': business,
'last_message': last_message,
'user': user,
})
else:
last_message = Message.objects.filter(
Q(sender=request.user, recipient=business.seller) |
Q(sender=business.seller, recipient=request.user)
).filter(business=business).order_by('-timestamp').first()
unread_businesses = set()
if Message.objects.filter(recipient=request.user, business=business, is_read=False).exists():
unread_businesses.add(business)
user_messages.append({
'business': business,
'last_message': last_message,
'unread_count': len(unread_businesses),
})
...
1.b. Обращайтесь с дисплеем user_messages
для ведения бизнеса с другими пользователями, используя message.user
:
{% for message in user_messages %}
{% if message.user %}
{# Handle display user_messages for business with other users #}
<a href="{% url 'user_messages' %}?business_slug={{ message.business.business_slug }}&username={{ message.user.username }}" class="list-group-item list-group-item-action border-0">
<div class="badge bg-success float-right">{{ individual_business_message_counter }}</div>
<div class="d-flex align-items-start">
<img src="https://ui-avatars.com/api/?name={{ message.user.username }}" class="rounded-circle mr-1" width="40px" height="40px">
<div class="flex-grow-1 ml-3">
{{ message.user.username }}
{% if message.last_message %}
<div class="small">{{ message.last_message.content }}</div>
{% else %}
<p>No messages yet.</p>
{% endif %}
</div>
</div>
</a>
{% else %}
<a href="{% url 'user_messages' %}?business_slug={{ message.business.business_slug }}" class="list-group-item list-group-item-action border-0">
<div class="badge bg-success float-right">{{ individual_business_message_counter }}</div>
<div class="d-flex align-items-start">
<img src="{{ message.business.profile_picture.url }}" class="rounded-circle mr-1" width="40px" height="40px">
<div class="flex-grow-1 ml-3">
{{ message.business.business_name }}
{% if message.last_message %}
<div class="small">{{ message.last_message.content }}</div>
{% else %}
<p>No messages yet.</p>
{% endif %}
</div>
</div>
</a>
{% endif %}
{% endfor %}
2.a. Запрос messages
на selected_business
с selected_user
, используя username
:
def user_messages_view(request):
...
selected_business = None
messages = []
if 'business_slug' in request.GET:
business_slug = request.GET.get('business_slug')
selected_business = get_object_or_404(Business, business_slug=business_slug)
if request.user == selected_business.seller and 'username' in request.GET:
# Query messages for selected_business with selected_user
username = request.GET.get('username')
selected_user = get_object_or_404(CustomUser, username=username)
messages = Message.objects.filter(
Q(sender= selected_user, recipient=selected_business.seller) |
Q(sender=selected_business.seller, recipient= selected_user)
).filter(business=selected_business).order_by('timestamp')
else:
messages = Message.objects.filter(
Q(sender=request.user, recipient=selected_business.seller) |
Q(sender=selected_business.seller, recipient=request.user)
).filter(business=selected_business).order_by('timestamp')
...
2.b. Обращайтесь к дисплею messages
с selected_business
:
{% for message in messages %}
{% if message.sender == request.user %}
...
{% elif selected_business.seller == request.user %}
{# Handle display messages from selected_business #}
<div class="chat-message-right pb-4">
<div>
<img src="{{ selected_business.banner_image.url }}" class="rounded-circle mr-1" alt="{{ selected_business.business_name }}" width="40" height="40">
<div class="text-muted small text-nowrap mt-2">{{ message.timestamp }}</div>
</div>
<div class="flex-shrink-1 bg-light rounded py-2 px-3 mr-3">
<div class="font-weight-bold mb-1">You</div>
{{ message.content }}
</div>
</div>
{% else %}
...
{% endif %}
{% endfor %}
2.c. Отображение рукояток selected_user
:
{% if selected_business %}
<div class="col-12 col-lg-7 col-xl-9">
<div class="py-2 px-4 border-bottom d-none d-lg-block">
<div class="d-flex align-items-center py-1">
{% if selected_user %}
{# Handle display selected_user #}
<div class="position-relative">
<img src="https://ui-avatars.com/api/?name={{ selected_user.username }}" class="rounded-circle mr-1" alt="{{ selected_user.username }}" width="40" height="40">
</div>
<div class="flex-grow-1 pl-3">
<strong>{{ selected_user.username }}</strong>
</div>
{% else %}
<div class="position-relative">
<img src="{{ selected_business.profile_picture.url }}" class="rounded-circle mr-1" alt="{{ selected_business.business_name }}" width="40" height="40">
</div>
<div class="flex-grow-1 pl-3">
<strong>{{ selected_business.business_name }}</strong>
</div>
{% endif %}
</div>
</div>