Создание объекта контекста со значениями из нескольких связанных моделей - PullRequest
0 голосов
/ 25 августа 2018

Я не могу понять это. Мое представление принимает аргумент для Team.id, и я хочу вернуть объект контекста с каждым User объектом с определенным значением в User.profile.team и соответствующей датой из Reports. Я чувствую, что начал на правильном пути, но что-то упустил. Вывод моего шаблона содержит все данные, которые я пытаюсь получить, но не так, чтобы их можно было логически отобразить.

В основном я использую модели, подобные следующим:

class Reports(models.Model):
    user = models.ForeignKey(User, null=True, on_delete=models.PROTECT)
    product = models.CharField(max_length=15)
    apps_activated = models.IntegerField(blank=True, null=True)
    prem_submitted = models.DecimalField(max_digits=30, decimal_places=2)

class Team(models.Model):
    name = models.CharField(max_length=255)
    leader = models.ForeignKey(User,on_delete=models.PROTECT)

Расширенный профиль пользователя:

class Profile(models.Model):
    COORDINATOR = 1
    LEADER = 2
    ADMIN = 3
    ROLE_CHOICES = (
        (COORDINATOR, 'Coordinator'),
        (LEADER, 'Leader'),
        (ADMIN, 'Admin'),
    )
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    team = models.ForeignKey(Team, on_delete=models.PROTECT,null=True)
    role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)

Самое близкое, что я нашел для получения нужных данных, это следующее:

team = 1
team_name = Team.objects.get(id=team)
team_users = User.objects.filter(profile__team=team).all()
team_stats = []

for user in team_users:
    team_stats.append(Reports.objects.filter(user_id=user.id))

С шаблоном, который выглядит следующим образом:

{% block content %}
<h1>{{ team }}</h1>
<ul>
{% for user in team_users %}
    <li><a href="/reports/user/{{ user.id }}">{{ user.first_name }} {{ user.last_name }}</a></li>
{% endfor %}
</ul>

<ul>
{% for stat in team_stats %}
    <li>
    {% for line in stat %}
        {{ line.product }} {{ line.type }} #etc #etc
        {% endfor %}
    </li>
{% endfor %}
</ul>

{% endblock %}

Я думал, что что-то понял с prefetch_related(), но не мог понять это. В идеале мне нужно было бы вернуть только один объект контекста в мой шаблон.

Edit:

Если это прояснит ситуацию, этот запрос возвращает результаты, которые я пытаюсь передать шаблону:

select auth_user.first_name, auth_user.last_name, r.product, r.apps_activated, r.prem_submitted, r.conversion_percentage, r.type
from auth_user
join home_profile
on auth_user.id = home_profile.user_id
join reports_reports as r
on auth_user.id = r.user_id
where home_profile.team_id = 1

, который возвращает строки, похожие на:

first_name-last_name-product-apps_activated-prem_submitted-conversion_rate-type    
user_1-user_1_last-product_1-693-139764.00-53.86-type1
user_1-user_1_last-product_2-74-27400.10-0.00-type1
user_1-user_1_last-product_3-102-19782.00-47.00-type2
user_2-user_2_last-product_1-7-2437.70-0.00-type2
user_2-user_2_last-product_2-52-10608.00-42.54-type3
user_2-user_2_last-product_3-260.40-0.00-type3

1 Ответ

0 голосов
/ 25 августа 2018

Потенциальное решение 1 :

Итак, я бы сделал следующее.Измените user в вашей модели Reports, чтобы явно указать ссылку на Profile (которая, в свою очередь, ссылается на пользователя)

class Reports(models.Model):
    profile = models.ForeignKey(Profile, null=True, on_delete=models.PROTECT)
    product = models.CharField(max_length=15)
    apps_activated = models.IntegerField(blank=True, null=True)
    prem_submitted = models.DecimalField(max_digits=30, decimal_places=2)

Вероятно, вы ищете, вероятно, ищетечто-то вроде запроса select_related(), добавив дополнительное поле ForeignKey для профиля:

reports = Reports.objects.select_related('profile')

Вы можете проверить полученный SQL с помощью str(reports.query), что должно привести кВ соответствии с тем, что вы обрисовали в своем вопросе.

Возвращенные значения курсора затем транслируются в соответствующие экземпляры модели ORM, так что когда вы зацикливаетесь на этих reports, вы получаете доступ к значениям связанных таблиц.через свои собственные объекты.Однако этот доступ по заранее выбранным прямым отношениям не вызовет дополнительных ударов по дб:

{% for report in reports %}
     {{ report.profile.user.username }}
     {{ report.product }}
     # ...
{% endfor %}

Дайте мне знать, как вы ладите, и если мы сможем найти более подходящее решение, если это не так?t.

Потенциальное решение 2 :

Возможно, другим решением, а возможно и самым простым из них, было бы иметь отношение ManyToMany в вашей модели Profile кReports:

class Profile(models.Model):
    COORDINATOR = 1
    LEADER = 2
    ADMIN = 3
    ROLE_CHOICES = (
        (COORDINATOR, 'Coordinator'),
        (LEADER, 'Leader'),
        (ADMIN, 'Admin'),
    )
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    team = models.ForeignKey(Team, on_delete=models.PROTECT,null=True)
    role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)
    reports = models.ManyToManyField(Reports, ...)

Тогда вы сможете выполнить цикл по users в шаблоне:

{% for user in users %}
    {% for report in user.reports.all %}
        {{ report.product }}
    {% endfor %}
{% endfor %}
...