Как фильтровать и отображать элементы «многие ко многим» в Django

#django #django-filter #manytomanyfield

#django #django-filter #manytomanyfield

Вопрос:

Я изучаю django и в своем проекте не могу понять, как правильно получать и отображать элементы из отношения «многие ко многим» на странице сведений о колоде.

model.py

 class Card(models.Model):
    def upload_path(self, filename):
        return os.path.join('cards/', filename)

    image = models.ImageField(upload_to=upload_path)
    card_num = models.CharField(max_length=20, default='')
    name = models.CharField(max_length=500, default='')
    desc = models.TextField(max_length=500, default='')
    card_class = models.OneToOneField(CardClass, on_delete=models.DO_NOTHING, default='')
    cost = models.OneToOneField(Cost, on_delete=models.DO_NOTHING, default='')
    card_type = models.OneToOneField(CardType, on_delete=models.DO_NOTHING, default='')
    rarity = models.OneToOneField(Rarity, on_delete=models.DO_NOTHING, default='')
    resource = models.IntegerField(default=None)
    attack = models.IntegerField(default=None)
    defence = models.IntegerField(default=None)


    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('card:cardPageDetail', args=[self.name])


class Deck(models.Model):

    def upload_path(self, filename):
        return os.path.join('decks/', filename)

    image = models.ImageField(upload_to=upload_path)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    cards_list = models.ManyToManyField(Card, related_name='cards_list')
    deck_id = models.CharField(max_length=10, default='')
    name = models.CharField(max_length=500, default='')
    desc = models.CharField(max_length=500, default='')
    price = models.CharField(max_length=500, default='')

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('card:deckPageDetail', args=[self.name])
  

views.py

 def deckPageDetail(request, name):
    deck=get_object_or_404(Deck, name=name)
    cards_all = Card.objects.all()
    queryset = cards_all.objects.filter(cards_list__in=deck.deck_id)
    print(queryset)
    context = {
        'deck': deck,
        'cards_in_deck': queryset,
    }
    return render(request, 'landing/deck_detail.html', context)
  

Я попробовал несколько решений, основанных на stackoverflow и uncle google, но безрезультатно.Я буду благодарен за помощь.

Ответ №1:

Вам просто нужно получить доступ к атрибуту card_list вашей колоды.

 deck = Deck.objects.get(id=1)
for card in deck.cards_list.all():
    print(card)
  

Комментарии:

1. Привет, спасибо за ответ. Он работает для определенного идентификатора колоды. Как я могу изменить его, чтобы распознать в deck = Deck.objects.get (id = 1), какая колода используется и какой у нее идентификатор, и на основе этого отображаемого списка карт. Вероятно, это вопрос новичка, но я только учусь. Спасибо 🙂

Ответ №2:

У вас уже есть колода с M2M, поэтому вы можете получить доступ к списку карт непосредственно в шаблоне. Во-первых, давайте очистим код, который не требуется.

 def deckPageDetail(request, name):
    deck=get_object_or_404(Deck, name=name)
    context = {
        'deck': deck,
    }
    return render(request, 'landing/deck_detail.html', context)
  

Затем внутри вашего landing/deck_detail.html шаблона вы можете перебирать карточки с помощью приведенного ниже кода.

 {% for card in deck.cards_list.all %}
    {{ card }}
{% endfor %}
  

и если вы хотите получить доступ к информации о картах

 {% for card in deck.cards_list.all %}
    {{ card }} {{ card.image.url }} {{ card.card_num }}
{% endfor %}
  

и на всякий случай, если вы хотели, чтобы это было в представлении

 def deckPageDetail(request, name):
    deck=get_object_or_404(Deck, name=name)
    queryset = deck.cards_list.all()
    print(queryset)
    context = {
        'deck': deck,
        'cards_in_deck': queryset,
    }
    return render(request, 'landing/deck_detail.html', context)