Django & SQLite.db – data is duplicated

Question:

I created 2 models in the Django framework. The first model is responsible to save emails and the second model to save messages. All emails and messages are saved in the SQLite.db. But when I add the same emails multiple times, the data base creates a new record and I don’t have a clue how can I manage saving data to retrieve multiple emails with the same name and then pass them as a one mutual email to the HTML template with all assigned messages to them.

An example:
I sent 3 messages from [email protected]. Messages: [‘Hi’, ‘Hello’, ‘Bonjour’] and one message from [email protected] [‘Hi’]
DB table:

Actual result:
3 records

  1. [email protected] | ‘Hi’
  2. [email protected] | ‘Hello’
  3. [email protected] | ‘Bonjour’
  4. [email protected] | ‘Hi’

Model:

class Email(models.Model):
    """The guest's email."""
    text = models.EmailField(max_length=100)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """Return a string representation of the model."""
        return self.text

class EmailMessage(models.Model):
    """The guest's message."""
    email = models.ForeignKey(Email, on_delete=models.CASCADE)
    message = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.message

Then I want to pass all data to the HTML template in order to display them:
url: /emails

def emails(request):
    """Show all emails."""
    emails = Email.objects.order_by('date_added')
    context = {'emails': emails}
    return render(request, 'home/emails.html', context)

HTML portion:
(I want to display only emails on this page, without messages, and when I click on each email, the user should be redirected to another page that display all messages assigned to a particular email.)

<h1>Emails</h1>

<ul>
    {% for email in emails %}
        <li>
            <a href="{% url 'home:email' email.id %}">{{ email.text }}</a>
        </li>
    {% empty %}
        <li>No emails have benn added yet.</li>
    {% endfor %}
</ul>

url: /emails/email_id

def email(request, email_id):
    """Show a single email and all its messages."""
    email = Email.objects.get(id=email_id)
    messages = email.emailmessage_set.order_by('-date_added')
    context = {'email': email, 'messages': messages}
    return render(request, 'home/messages.html', context)

Template:

<h1>Email: {{ email }}</h1>

<ul>
    {% for message in messages %}
        <li>
            <p>{{ message.date_added|date:'M d, Y H:i' }}</p>
            <p>{{ message|linebreaks }}</p>
        </li>
    {% empty %}
        <li>No emails have benn added yet.</li>
    {% endfor %}
</ul>

But the final result is:

  1. [email protected]

message_1: Hi

  1. [email protected]

message_1: Hello

  1. [email protected]

message_1: Bonjour

  1. [email protected]

message_1: Hi

Expected result:

  1. [email protected]

message_1: Hi

message_2: Hello

message_3: Bonjour

  1. [email protected]

message_1: Hi

enter image description here
!!! Messages are available when I click on a particular email! So when User click on a particular email, he will be redirected to another page with all messages.

The question is how to handle it? And should I modify the HTML (javascript), view function or created models? Which approach is the best to make my page more stable?

Asked By: Maxwell

||

Answers:

We can pass the EmailMessages with:

def emails(request):
    messages = EmailMessage.objects.select_related('email').order_by('date_added')
    context = {'messages': messages}
    return render(request, 'home/emails.html', context)

You can {% regroup … %} [Django-doc] the messages by email address:

<h1>Emails</h1>

<ul>
    {% regroup messages by email.text as message_group %}
    {% for email, messages in message_group %}
        <li>
            {{ email }}:
            <ul>
            {% for message in messages %}
                <a href="{% url 'home:email' message.pk %}">{{ message.message }}</a>
            {% endfor %}
            </ul>
        </li>
    {% empty %}
        <li>No emails have been added yet.</li>
    {% endfor %}
</ul>
Answered By: Willem Van Onsem

I added simple try-except block that solve this problem:

if form_email.is_valid() and form_message.is_valid():
        try:
            email = Email.objects.get(text=request.POST['text'])
        except:
            form_email.save()
            email = Email.objects.last()
        
        message = form_message.save(commit=False)
        message.email = email
        message.save()
Answered By: Maxwell
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.