Building a Social Media App With Python 3 and Django Beginners Tutorial Finishing DMs

LegionScript
4 min readMay 9, 2021

Video Tutorial

Code on Github

In this tutorial, we will add some extra features to our direct messages. We will add a notification when a user receives a message, we will add an alert if a thread is created with a username that doesn’t exist. We will also add the ability to upload images inside of messages as well. Finally, we will change some CSS styles as well. Let’s get started by adding a notification when a message is created.

Adding a Notification for Messages

First we need to add another notification type, we will need to add a thread field and we will add a comment to keep track of the notification types. We can make a notification inside of our CreateMessage view to send it after the user sends a message. We need to send this to the receiving user on the message.

models.py

class Notification(models.Model):  # 1 = Like, 2 = Comment, 3 = Follow, 4 = DM  notification_type = models.IntegerField(null=True, blank=True)  to_user = models.ForeignKey(User, related_name='notification_to', on_delete=models.CASCADE, null=True)  from_user = models.ForeignKey(User, related_name='notification_from', on_delete=models.CASCADE, null=True)  post = models.ForeignKey('Post', on_delete=models.CASCADE, related_name='+', blank=True, null=True)  comment = models.ForeignKey('Comment', on_delete=models.CASCADE, related_name='+', blank=True, null=True)  thread = models.ForeignKey('ThreadModel', on_delete=models.CASCADE, related_name='+', blank=True, null=True)  date = models.DateTimeField(default=timezone.now)  user_has_seen = models.BooleanField(default=False)

views.py

notification = Notification.objects.create(notification_type=4, from_user=request.user, to_user=receiver, thread=thread)

Now that we have our view set up, we need to update our template tag in the show_notifictations.html. We will need to add another type in an elif after we check for a post. We can then add some text to alert the user that another user sent them a message.

social/templates/show_notifications.html

{% elif notification.thread %}  <div class="dropdown-item-parent">    <a href="{% url 'thread-notification' notification.pk notification.thread.pk %}">@{{ notification.from_user }} sent you a message</a>    <span class="dropdown-item-close" onclick="removeNotification(`{% url 'notification-delete' notification.pk %}`, `{{ request.path }}`)">&times;</span>  </div>

Adding a User Not Found Message

If a user tries creating a thread with a user that doesn’t exist, right now we just redirect back to the same page to have them try again, we need to give them some feedback so they know that it failed. We will use the Django Messages Framework to handle this easily. The messages framework will automatically handle creating the message and removing it once the user sees it. So all we need to do is create a message when we want to and then add a place in our template to check for messages. First let’s create a message after the user enters an invalid username. This will be done inside of our CreateThread view in the post method.

views.py

def post(self, request, *args, **kwargs):  form = ThreadForm(request.POST)  username = request.POST.get('username')  try:    receiver = User.objects.get(username=username)    if ThreadModel.objects.filter(user=request.user, receiver=receiver).exists():      thread = ThreadModel.objects.filter(user=request.user, receiver=receiver)[0]      return redirect('thread', pk=thread.pk)  if form.is_valid():    sender_thread = ThreadModel(      user=request.user,      receiver=receiver    )    sender_thread.save()    thread_pk = sender_thread.pk
return redirect('thread', pk=thread_pk)
except: messages.error(request, 'User not found.') return redirect('create-thread')

Next let’s check for messages in our templates and display them as a bootstrap alert.

templates/social/create_thread.html

<div class="row justify-content-center mt-3 mb-5">  <div class="col-md-5 col-sm-12">    {% if messages %}    {% for message in messages %}    <div class="alert alert-danger" role="alert">    {{ message }}    </div>  {% endfor %}  {% endif %}  <form method="POST">    {% csrf_token %}    <p>Enter the username for the person you would like to talk to.</p>    {{ form | crispy }}    <div class="d-grid gap-2">      <button type="submit" class="btn btn-success mt-3">Continue</button>    </div>  </form>  </div></div>

Adding Image Uploads in DMs

Right now we can only upload text in our messages, let’s add the ability to add images as well. This is going to work similar to how we added images to posts. We will need to have a form with an image field and we will need to update our views.py to handle saving the image. We also need to update our template as well.

We will change our MessageForm to a ModelForm to make it easy to save.

forms.py

class MessageForm(forms.ModelForm):  body = forms.CharField(label='', max_length=1000)  image = forms.ImageField(label='Send an Image', required=False)  class Meta:    model = MessageModel    fields = ['body', 'image']

Next we need to update our views to save this form data in the database.

views.py

class CreateMessage(View):def post(self, request, pk, *args, **kwargs):  form = MessageForm(request.POST, request.FILES)  thread = ThreadModel.objects.get(pk=pk)  if thread.receiver == request.user:    receiver = thread.user  else:    receiver = thread.receiver  if form.is_valid():    message = form.save(commit=False)    message.thread = thread    message.sender_user = request.user    message.receiver_user = receiver    message.save()  notification = Notification.objects.create(notification_type=4, from_user=request.user, to_user=receiver, thread=thread)  return redirect('thread', pk=pk)

The last piece to this is that we need to update our template to show the image. I’m not going to put the code here for that since it is a large file but it will be available in the github repository at the top of this article. That code will look very similar to the post code except we have some extra CSS styles to put the messages and images on the left or right.

Adding the Mail Icon

Finally, we will add an icon to the inbox next to each username on the thread. Right now it just looks a little plain and this will just add a little more to the page.

{% for thread in threads.all %}  <div class="row mb-3">    <div class="card col-md-12 p-5 shadow-sm">      <h5><i class="far fa-envelope inbox-icon"></i>@{{ thread.receiver }}</h5>      <a class="stretched-link" href="{% url 'thread' thread.pk %}"></a>    </div>  </div>{% endfor %}

That is it for this tutorial, we will come back to add more later but this will be a good stopping point for now.

--

--