Как я могу получить доступ к другому полю связанной таблицы ManyToMany? - PullRequest
0 голосов
/ 19 июня 2020

Допустим, у меня есть следующие модели:

class Publication(models.Model):
    title = models.CharField(max_length=30)

class Article(models.Model):
    headline = models.CharField(max_length=100)
    publications = models.ManyToManyField(Publication)
    upload = models.ForeignKey(related_name='x1', Uploads)

class Uploads(models.Model):
    topic = models.CharField(max_length=100)

Я хочу выбрать все статьи указанного c загрузить топи c вместе с их публикацией заголовком . Таким образом, мой результат должен быть:

<QuerySet [
    {'id': 1, 'headline': 'headline1', 'publications': 'publication title 1'}, 
    {'id': 2, 'headline': 'headline2', 'publications': 'publication title 2'},
]

В настоящее время у меня есть это:

(
    Article.objects.filter(upload__topic='sports')
    .values('id', 'headline', 'publications')
)

, что дает мне следующее:

<QuerySet [
    {'id': 1, 'headline': 'headline1', 'publications': 1}, 
    {'id': 2, ''headline': 'headline2', 'publications': 2},
]

Я знаю, что могу oop поверх QuerySet и для каждой публикации запускайте другой запрос БД к таблице Publication, чтобы получить соответствующий заголовок, но мне интересно, есть ли лучший способ сделать это. Может быть, с помощью одного запроса?

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Вы запрашиваете «заголовок публикации» нужных статей, но у вас есть отношение «многие ко многим» от статьи к публикации, поэтому (в общем) будет много «заголовков публикации» для каждой. article.

Чтобы получить их все, вы можете использовать prefetch_related() для прохождения отношения «многие ко многим». Это выполнит второй запрос, но в целом это довольно эффективный способ выполнения, который позволяет django предоставить все свои стандартные возможности ORM.

articles = (
    Article.objects
    .filter(upload__topic='sports')
    .prefetch_related('publications')
)
# Iterate over causes two database queries, 
# - one to select the relevant articles
# - second to select the publications for those articles. These
#   are cached in the related manager so...
for article in articles:
    # ...this should not perform another database query.
    # article.publications.all() is cached.
    print([pub.title for pub in article.publications.all()])

Вы хотели, чтобы один набор запросов получил все значения в одном go. Вы можете сделать это, но вы получите несколько записей для статей с несколькими публикациями:

# using articles from above
articles.values_list('headline', 'publications__title')

Итак, если статья с заголовком «Мой заголовок» имеет две публикации с заголовками «Заголовок 1» и «Заголовок 2» вы получите:

[("My Headline", "Title 1"), ("My Headline", "Title 2")]

На мой взгляд, лучше всего использовать экземпляры модели, возвращаемые articles, без использования values_list().

0 голосов
/ 19 июня 2020

Ну, есть запрос, который позволяет это сделать. Сначала go в оболочке, написав python manage.py shell. Затем напишите следующее: `

from appName.models import *
publications = Publication.objects.all()
first_pub = publications.first()
first_pub.article_set.all()

` Имя приложения должно соответствовать приложению, в котором находится модель. строка 2 получает все объекты в вашей модели публикации. строка 3 получает первый объект (вы можете получить любой объект, который хотите). Строка 4 получает все статьи из статьи, поскольку она связана. Часть article в article_set - это имя модели Article.

Таким образом, используя эту идею, вы можете отобразить все статьи на странице, перейдя в views.py и написав:

from django.shortcuts import render
from .models import Publication


def index(request):
    publications = Publication.objects.all()

    return render(request, "home/index.html", {"publications": publications})

и в вашем html:

<body>
  {% for publication in publications %}
  {% for i in publication.article_set.all %}
  <h2>{{ i }}</h2>
  {% endfor %}
  {% endfor %}
</body>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...