Избегайте дублирования в цикле Django for с отношением "многие ко многим

Моя цель - перечислить названия тегов для каждой созданной заметки.

У меня возникают проблемы, потому что tag_title и note связаны через отношения "многие ко многим".

Как я обычно это делаю:

{% for note_tag in note_tags %}
    {% if note_tag.note == note %}
        {{note_tag.tag_title}}
    {% endif %}
{% endfor %}

Однако, поскольку tag_title имеет отношение "многие ко многим" с NoteModel, note_tag.note выдает notes.NoteModel.None

Мои models.py выглядят следующим образом:


class NoteModel(models.Model):
    note = models.CharField(
        max_length = 5000,
    )

    note_title = models.CharField(
        max_length = 500,
        blank = False,
        null = True,
    )
    
    project = models.ForeignKey(
        IndividualProject,
        on_delete=models.CASCADE,
        related_name = "note_projects",
        blank = False,
        null = True,
    )

    tag = models.ManyToManyField(
        'NoteTagModel',
        related_name="tags",
        blank= False,
        through = "TaggedModel"
    )

    def __str__(self):
        return f"{self.note_title}"

class NoteTagModel(models.Model):
    note = models.ManyToManyField(
        'NoteModel',
        related_name="tag_notes",
        blank= False,
        through = "TaggedModel"
    )

    tag_title = models.CharField(
        max_length = 200,
        default = "General",
    )

    def __str__(self):
        return f"{self.tag_title}"

class TaggedModel(models.Model):
    note = models.ForeignKey(NoteModel, on_delete = models.CASCADE)
    tag = models.ForeignKey(NoteTagModel, on_delete = models.CASCADE)

    def __str__(self):
        return f"{self.note} | {self.tag}"

class TagCommentaryModel(models.Model):
    tag_title = models.ForeignKey(
        NoteTagModel,
        on_delete=models.CASCADE,
        related_name="tag",
        blank = False,
        null = True,
    )

    tag_commentary = models.CharField(
        max_length = 5000
    )

    def __str__(self):
        return f"Tag: {self.tag_title} | Tag Commentary: {self.tag_commentary}"

Контекст в моем views.py выглядит следующим образом:

context = {
        'note_form' : note_form,
        'notes' : NoteModel.objects.filter(project = obj),
        'notes_tag' : NoteTagModel.objects.all(),
        'commentary' : TagCommentaryModel.objects.all(),
        'projects' : IndividualProject.objects.all(),
        'specific_project' :  IndividualProject.objects.get(id=id),
        'obj' : IndividualProject.objects.get(id=id),
        'tagged' : TaggedModel.objects.all(),
        
    }

Мой шаблон django выглядит следующим образом:

<div class = note_overview_container>
    {% for note in notes %} 
        <div class = individual_note_container> 
                <div class = note_title>
                {{ note.note_title }}
                </div>
                {% for note_tag in notes_tag %}
                    <div class = tag_title>
                    {{ note_tag.tag_title }}
                    </div>
                <ul class = tag_commentary>
                {% for commentary in commentary %}
                        {% if note_tag == commentary.tag_title %}
                            {% if note == commentary.note %}
                            <li>{{ commentary.tag_commentary }}</li>
                            {% endif %}
                        {% endif %}
                {% endfor %}
                </ul>
                {% endfor %}
        </div>
    {% endfor %}    
</div>

Любая помощь будет очень признательна

На мой взгляд, вы можете значительно упростить свои модели. Вы указываете от тега в NoteModel к NoteTagModel и наоборот & я не думаю, что это необходимо. Также TaggedModel кажется излишней. По крайней мере, если нет конкретной причины связывать их так, как вы это сделали.

class NoteModel(models.Model):
    note = models.CharField(max_length = 5000)
    note_title = models.CharField(max_length=500, blank=False, null=True)
    project = models.ForeignKey(IndividualProject, on_delete=models.CASCADE, related_name="note_projects", blank=False, null=True)
    // plural
    tags = models.ManyToManyField(NoteTagModel, related_name="tags", blank=False)
    
    def __str__(self):
        return self.note_title
    
class NoteTagModel(models.Model):
    // usually there is no need to point here again to the same model thats already pointing to this one
    tag_title = models.CharField(max_length=200, default="General")
    
    def __str__(self):
        return self.tag_title

Если вы хотите получить обратный доступ от NoteTagModel к NoteModel, вы можете сделать следующее, например:

for tag in NoteTagModel.objects.all():
    for note in tag.nodemodel_set.all():
        print(note.note_title)
        …

(я заключил html-классы в двойные кавычки)

<div class="note_overview_container">
    {% for note in notes %}
        <div class="individual_note_container"> 
            <div class="note_title">
                {{ note.note_title }}
            </div>

            <!-- loop over all the tags related to the note -->
            {% for tag in note.tags.all %}
                <div class=”tag_title”>
                    {{ tag.tag_title }}
                </div>

                <ul class="tag_commentary">
                    // commentary in commentary shouldnt be named the same
                    {% for comment in commentary %}
                        {% if note_tag == comment.tag_title %}
                            {% if note == comment.note %}
                                <li>{{ comment.tag_commentary }}</li>
                            {% endif %}
                        {% endif %}
                    {% endfor %}
                </ul>
            {% endfor %}
        </div>
    {% endfor %}    
</div>
Вернуться на верх