Показать список связанных объектов в Django

У меня проблема с отображением списка связанных статей в моем Q&A DetailView. У меня есть поле, где пользователь может подключить статью к Q&A из админки. Я хочу отобразить эти связанные статьи

models.py

class QA(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
    title = models.CharField(max_length=750)
    category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
    related_articles = models.ManyToManyField(Article, default=None, blank=True, related_name='related_article')

    slug = models.SlugField(unique=True, blank=True)

class Article(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
    title = models.CharField(max_length=200)
    category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
    slug = models.SlugField(unique=True, blank=True)

views.py

class QADetailView(LoginRequiredMixin, DetailView):
    login_url = 'login'
    redirect_field_name = 'login'
    template_name = 'QADetailView.html'
    model = QA

    def get_context_data(self, **kwargs):
            categories = Category.objects.all()                        
            related_articles = Article.objects.filter(related_article=self.kwargs['id']) #No idea what to put in filter
            #related_articles = Article.objects.filter(related_article='1')
                
            context['related_article'] = related_articles
            context['categories'] = categories
            
            return context

QADetailView.html

{% for article in related_article %}
   {{article.title}}
{% endfor %}

Вам не нужно вводить связанные статьи в контекст шаблона, вы можете просто написать в вашем шаблоне QADetailView.html (без необходимости редактирования):

{% for article in object.related_articles.all %}
   {{article.title}}
{% endfor %}

Сначала проверьте решение RedWheelBorrow. Если оно не работает. Попробуйте следующее:

Возможно, существует лучший способ структурирования классов. Так, в Django можно имитировать иерархию. Например, при создании представления счета-фактуры это будет выглядеть примерно так.

from django.db import models


class Invoice(models.Model):
    """Representing a invoice"""
    user = models.ForeignKey(to=User, on_delete=models.PROTECT, related_name="invoices", default=1)
    title = models.CharField(max_length=200)
    date = models.DateField()
    start_time = models.TimeField(default=time(9))
    duration = models.IntegerField(default=1)
    invoice_number = models.CharField(max_length=500, default=increment_invoice_number) # increment_invoice_number this a function that I will leave out of this answer


class InvoiceLine(models.Model):
    """Representing invoice lines of an invoice"""
    invoice = models.ForeignKey(to=Invoice, on_delete=models.CASCADE, related_name="lines")
    description = models.CharField(_("Beschrijving"), max_length=512)
    quantity = models.IntegerField(_("Aantal"), blank=True, default=1)
    discount = models.IntegerField(_("Korting in %"), default=0)



Обратите внимание, что представленному здесь представлению счета-фактуры не хватает некоторых атрибутов, чтобы быть полностью функциональным классом в производстве. Ему все еще нужны налоговые ссылки и т.д. Тем не менее, оно содержит решение вашей проблемы.

Класс Invoice имеет атрибут user, который содержит ForeignKey с 'invoices' в качестве связанного имени. Это означает, что объект должен быть связан с объектом User. Пользователь может иметь несколько счетов-фактур. Счет-фактура может быть связан только с одним пользователем. Это отношение "один ко многим":

User -> List[Invoice,...]

При рассмотрении класса InvoiceLine мы видим аналогичную картину. Атрибут invoice является ForeignKey со ссылкой на класс Invoice и содержит 'lines' в качестве связанного имени. Это также отношение "один-ко-многим".

Invoice -> List[InvoiceLine, ...]

Для получения связанных объектов мы можем использовать следующий код:

# obtain user
user =  User.objects.get(id=<USER_ID>)

# obtain all Invoice objects linked to user
invoices = user.invoices.all()

# print all string representations of Invoice objects
print(invoices)

# obtain all InvoiceLine objects linked to invoices
for invoice in invoices:
    lines = invoice.lines.all()
    print(lines)

В приведенном выше примере самым верхним объектом является User. Пользователь может содержать несколько объектов Invoice. Объект Invoice может содержать несколько объектов InvoiceLine. Мы можем использовать ту же стратегию для решения вашей проблемы.

Мы хотим получить следующее представление:

User -> List[QA, ...] QA -> List[Article, ...]



class QA(models.Model):
    id = models.AutoField(primary_key=True)

    # So in your case the author is the user. 
    # Here you define User -> List[QA, ...] 
    author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS

    title = models.CharField(max_length=750)
    category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
    slug = models.SlugField(unique=True, blank=True)

    # related_articles is removed.


class Article(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL) #settings INSTALLED_APPS
    title = models.CharField(max_length=200)
    category = models.ForeignKey(Category, on_delete = models.CASCADE, blank=True)
    slug = models.SlugField(unique=True, blank=True)**
    related_articles = models.ForeignKey(to=QA, on_delete=models.CASCADE, related_name="related_articles")


class QADetailView(LoginRequiredMixin, DetailView):
    login_url = 'login'
    redirect_field_name = 'login'
    template_name = 'QADetailView.html'
    model = QA

    def get_context_data(self, **kwargs):
            categories = Category.objects.all()

            # obtain specific QA
            qa = QA.objects.get(pk=id, author=self.request.user)) # check how you named the id variable in your url.

            # obtain related articles
            related_articles = qa.related_articles.all()

            # Save in context for use in template.
            context['related_articles'] = related_articles # Added an character 's' to key value for there is can be more than one related article.
            context['categories'] = categories
            
            return context


{% for article in related_articles %}   # Also add character 's' here
   {{article.title}}
{% endfor %}

Это должно помочь. Хотя, возможно, есть некоторые улучшения в обработке ошибок. Я надеюсь, что это работает. Если нет, дайте мне знать.

Вернуться на верх