chris-profico
chris-profico

Reputation: 911

Retrieve a user list from a manydomanyfield with information from an intermediate table

it's been a few hours since I tried to retrieve a list of users with the information of an intermediate table.

So I have a workspace model that is a manytomanyfield with users

There is also an intermediary table to differentiate the classic users and the workspace manager

I would like to display the list of users and add a small icon symbolizing the managers in the list.

But unfortunately it seems difficult for Django, to display both the list of users of the workspace with the information of the intermediate table.

In any case I look at the documentation of Django I have not managed to find how to do.

models.py

class Workspace(models.Model):
    name = models.CharField(max_length=250, verbose_name="Nom du workspace")
    members = models.ManyToManyField(User, through='Membership', verbose_name="Membres du workspace")
    token = models.CharField(max_length=500)    # token statique
    join_token = models.CharField(max_length=500)   # token dynamique
    join_token_date = models.DateTimeField(auto_now_add=False, null=True, blank=True)
    payday = models.DateField(max_length=10, verbose_name="Jour de paye", null=True, blank=True)
    planning_image = ProcessedImageField(upload_to='planning',
                                                null=True, 
                                                blank=True,
                                                processors=[ResizeToFill(1299, 937)],
                                                format='JPEG',
                                                options={'quality': 100})
    planning_thumbnail = ImageSpecField(source='planning_image',
                                        processors=[ResizeToFill(280, 202)],
                                        format='JPEG',
                                        options={'quality': 100})

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('create-workspace')


class Membership(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
    is_manager = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)

views.py

@login_required
def workspace_detail(request, token):

    ins_workspace = get_object_or_404(Workspace, token=token)
    list_members = ins_workspace.members.all()

    for member in list_members:
        if member == request.user:
            current_user = Membership.objects.get(workspace=ins_workspace, user=request.user)
            context = {
                        'name': ins_workspace.name,
                        'token': ins_workspace.token,
                        'list_members': list_members,
                        'payday': ins_workspace.payday,
                        'is_manager': current_user.is_manager,
                        }
            return render(request, 'workspace/workspace_detail.html', context)
        else:
            return HttpResponseForbidden()

template.html

{% for item in list_members %}
   {{ item.username }}
{% endfor %}

This is what I want:

template.html

{% for item in list_members %}
   {% item.is_manager %}
      {{ item.username }} (♔)
   {% else %}
      {{ item.username }}
{% endfor %}

Upvotes: 1

Views: 51

Answers (1)

ruddra
ruddra

Reputation: 51988

You can do it like this:

Update Membership model with related name:

class Membership(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="membership")
    workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
    is_manager = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)

Then you can update your view like following:

from django.db.models import F

@login_required
def workspace_detail(request, token):

    ins_workspace = get_object_or_404(Workspace, token=token)
    list_members = ins_workspace.members.all().annotate(is_manager=F('membership__is_manager'))

    context = {
            'name': ins_workspace.name,
            'token': ins_workspace.token,
            'list_members': list_members,
            'payday': ins_workspace.payday,
            'is_manager': request.user.membership.get(workspace=ins_workspace).is_manager,
     }
     return render(request, 'workspace/workspace_detail.html', context)

That should do the trick.

Here what I have done is that, I am using a reverse relation to get is_manager value from membership model. I am annotating that value in the queryset using F.

Upvotes: 1

Related Questions