bgarcial
bgarcial

Reputation: 3193

Making queries ManyToMany relationships

I have a model named AffectedSegment which is used for store a corporal segments selection.

class AffectedSegment(models.Model):

    SEGMENTO_ESCAPULA = 'Escápula'
    SEGMENTO_HOMBRO = 'Hombro'
    SEGMENTO_CODO = 'Codo'
    SEGMENTO_ANTEBRAZO = 'Antebrazo'
    SEGMENTO_CARPO_MUNECA = 'Carpo/Muñeca'
    SEGMENTO_MANO = 'Mano'
    SEGMENT_CHOICES = (
        (SEGMENTO_ESCAPULA, u'Escápula'),
        (SEGMENTO_HOMBRO, u'Hombro'),
        (SEGMENTO_CODO, u'Codo'),
        (SEGMENTO_ANTEBRAZO, u'Antebrazo'),
        (SEGMENTO_CARPO_MUNECA, u'Carpo/Muñeca'),
        (SEGMENTO_MANO, u'Mano'),
    )

    affected_segment = models.CharField(
        max_length=12,
        choices=SEGMENT_CHOICES,
        verbose_name='Affected Segment'
    )

    def __str__(self):
        return "%s" % self.affected_segment

I have another model named Movement, which is used for store a movement asociated or related with the previous corporal segment entered.

The idea is that one segment (AffectedSegment object) can have many movements, and one movement (Movement object) can be associated with one or many segments.

class Movement(models.Model):
    type = models.CharField(
        max_length=255,
        verbose_name='Movement type'
    )

    corporal_segment_associated = models.ManyToManyField(
        AffectedSegment,
        blank=True,
        verbose_name='Affected segment associated')

    def __str__(self):
        return "%s" % self.type

This two models, I am referencing in this model

class RehabilitationSession(models.Model):

    affected_segment = models.ManyToManyField(
    AffectedSegment,
    verbose_name='Segmento afectado',
    #related_name='affectedsegment'
    )

    movement = models.ManyToManyField(
    Movement,  # Chained Model
    verbose_name='Movement',
    #related_name = 'movement'
)     

My main doubt is How to can I lookup the content of affected_segment and movement fields from RehabilitationSession model in my html templates.

I am trying pass these data of this way:

My views.py file

class RehabilitationSessionList(ListView):

    queryset = RehabilitationSession.objects.all()
    context_object_name = 'rehabilitationsessions'
    template_name = 'finals_list.html'

And my finals_list.html template is:

<thead>
     <tr>
         <th>Affected Segment</th>
     </tr>
</thead>
<tbody>
{% for a in rehabilitationsessions %}
<tr>   
    <td>{{ a.affected_segment }}</td>
</tr>
</tbody>
{% endfor %}

But when I access to my template via url, I get this:

enter image description here

Of course, the RehabilitationSession model does not have the affected_segment and movement fields explicitly declared, due to that the ManyToMany relationships create another intermediate models/tables of this way:

enter image description here

Via Django Shell, I can make the queries, navigating through of some of this tables/models

In [21]: RehabilitationSession.objects.filter(movement__type='Extensión')
Out[21]: <QuerySet [<RehabilitationSession: Andrea Vermaelen>]>

In [24]: RehabilitationSession.objects.filter(affected_segment__affected_segment='Codo
...: ')
Out[24]: <QuerySet [<RehabilitationSession: Andrea Vermaelen>]>

My question is how to can I make the queries in my views for the data appear in the templates,

Is possible that my models are not defined correctly? ...

I know that this should not be complex, but I would like receive some orientation about it for I retrieve the segments and movements of a person in a rehabilitation session.

Any orientation is welcome

UPDATE

In relation to the support that @Daniel-Roseman gave me, I extract also the movement field for attach it in the table.

{% for a in rehabilitationsessions %}
                {% for r in a.affected_segment.all %}
                    {% for l in a.movement.all %}
                         <tr>
                            <td>{{ a.id }}</td>
                            <td>{{ a.patient.full_name }}</td>
                            <td>{{ a.patient.user.birth_date }}</td>
                            <td>{{ a.patient.user.age }}</td>
                            <td>{{ a.patient.user.sex }}</td>
                            <td>{{ a.upper_extremity }} <br/><br/> 
                                <strong>{{ a.pain_extremity }}</strong> </td> 
                            <td>{{ a.patient.dominant_superior_member }}</td>
                            <td>{{ r.get_affected_segment_display }}</td>

                            <td>{{ l }}</td>
                            <td> <button type="button" class="btn btn-xs btn-info"><a href="{% url 'rehabilitationsessions:detail' a.id %}">Ver</a></button></td> 
                            <td><a href="{% url 'rehabilitationsessions:edit' a.id %}">Editar</a></td>

                          </tr>
                    {% endfor %}
                {% endfor %}
            {% endfor %}

And the movement it's showed. Works. But when I edit the register for add some additional movement or additional affected_segment, the behavior is that is showed one new record of the this additional segment or movement, although it's not a new record in the database, is a new line of the same record ...

I think that this happened due to my three for loops ... It's something like this https://cldup.com/JRKuSRFPuD.png

Upvotes: 0

Views: 109

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599610

As you've said, affected_segment is a many-to-many field. That means it refers to many segments (and the name seems wrong, it should be plural). So you can't just output it, you need to iterate through it:

{% for a in rehabilitationsessions %}
   {% for r in a.affected_segment.all %}
       {{ r.get_affected_segment_display }}
   {% endfor %}
{% endfor %}

See that since the field you're interested in on AffectedSegment, itself called affected_segment, has choices assigned, you can use get_affected_segment_display to display the readable value of the choice.

Upvotes: 1

Related Questions