Я работаю над проектом, чтобы записать все оценки, снятые на кучу событий стрельбы из лука. Они застрелены многими людьми на многих мероприятиях и во многих различных раундах стрельбы из лука. («Раунд» в стрельбе из лука - это особый тип соревнований. Для простоты, скажем, их два: в помещении и на улице.)
Вот базовая c диаграмма ER соответствующей части моего модель базы данных:
┌───────────┐ ┌───────────┐ ┌────────────────┐ ┌───────────┐
│ │ ╱│ │╲ │ │╲ │ │
│ Person │──────┼──│ Score │──┼────│ EventRound │──┼─────│ Event │
│ │ ╲│ │╱ │ │╱ │ │
└───────────┘ └───────────┘ └────────────────┘ └───────────┘
╲│╱
┼
│
┌───────────┐
│ │
│ Round │
│ │
└───────────┘
Вы можете видеть, что здесь работают две связи ManyToMany, решаемые с помощью двух соединительных таблиц (EventRound
и Score
). Я создаю эти соединительные таблицы вручную, указав таблицу «through» и «through_fields» в models.py.
Я создал PersonDetailView, который позволяет мне получать доступ и проходить через все оценки в Score
таблица для конкретного c человека. (Благодаря Jaberwocky и его решению в Detailview Object Relations )
# views.py
class PersonDetailView(DetailView):
model = Person
queryset = Person.objects.all()
template_name = 'person_detail.html'
def get_context_data(self, **kwargs):
context = super(PersonDetailView, self).get_context_data(**kwargs)
context['scores'] = Score.objects.filter(person=self.get_object()).order_by('-event_round__date')
return context
# person_detail.html
{% block content %}
<h1>Results for {{ person }}</h1>
<table>
<tr><th>Division</th><th>Score</th><th>Date</th><th>Event</th><th>Round</th></tr>
{% for score in scores %}
<tr>
<td>{{ score.division }}</td>
<td>{{ score.pretty_score }}</td>
<td>{{ score.event_round.date|date:"M d, Y" }}</td>
<td>{{ score.event_round }}</td>
<td>{{ score.event_round.round }}</td>
</tr>
{% endfor %}
</table>
{% endblock content %}
Проблема возникает, когда я пробую ту же стратегию с событиями и раундами. Я хотел бы показать все оценки, связанные с определенным событием или раундом, и включить подробную информацию о человеке, который снял счет.
Я не могу понять, как достичь через EventRound
таблицы и получите результаты, хранящиеся в Score
. Предположительно, мне нужно дополнительно манипулировать context
в get_context_data
методе PersonDetailView
.
Любые идеи о том, как это сделать?
Обновление: Вот часть моего models.py, который включает таблицы, на которые есть ссылки в этом посте.
from django.db import models
from datetime import date
from django.urls import reverse
from django.utils import timezone
class Person(models.Model):
"""
Contains information about competitors who have scores in the database.
"""
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=75)
birthdate = models.DateField(blank=True, null=True)
slug = models.SlugField(null=False, unique=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = "People"
ordering = ['last_name', 'first_name']
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
def get_absolute_url(self):
return reverse('person_detail', kwargs={'slug', self.slug})
class Event(models.Model):
name = models.CharField(max_length=100)
start_date = models.DateField(null=True)
end_date = models.DateField(null=True)
location = models.ForeignKey("Location", on_delete=models.CASCADE)
slug = models.SlugField(null=False, unique=True)
scoring_method = models.ForeignKey("ScoringMethod", on_delete=models.CASCADE)
event_type = models.ForeignKey("EventType", blank=True, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['name']
def __str__(self):
return f"{self.name}"
def get_absolute_url(self):
return reverse('event_detail', kwargs={'slug', self.slug})
@property
def date_range(self):
if self.start_date is None:
return "Unknown"
elif self.start_date == self.end_date:
return f"{self.start_date.strftime('%b %d, %Y')}"
else:
return f"{self.start_date.strftime('%b %d, %Y')} – {self.end_date.strftime('%b %d, %Y')}"
IN_OR_OUT_CHOICES = [
("Indoor", "Indoor"),
("Outdoor", "Outdoor"),
]
class Round(models.Model):
name = models.CharField(max_length=75)
description = models.TextField()
slug = models.SlugField(null=False, unique=True)
organization = models.ForeignKey("Organization", on_delete=models.CASCADE)
is_retired = models.BooleanField("Retired", default=False)
in_or_out = models.TextField(
"Indoor/Outdoor",
max_length=30,
choices=IN_OR_OUT_CHOICES,
)
events = models.ManyToManyField(
Event,
through="EventRound",
through_fields=('round', 'event'),
related_name="rounds",
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['organization', 'name']
def __str__(self):
return "%s" % (self.name)
def get_absolute_url(self):
return reverse('round_detail', kwargs={'slug', self.slug})
class EventRound(models.Model):
date = models.DateField(null=True)
event = models.ForeignKey("Event",
on_delete=models.CASCADE,
related_name="event_rounds",
)
round = models.ForeignKey(
"Round",
on_delete=models.CASCADE,
related_name="event_rounds",
)
participants = models.ManyToManyField(
Person,
through="Score",
through_fields=('event_round', 'person'),
related_name="event_rounds",
)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = "Event-Rounds"
ordering = ['-event']
def __str__(self):
return "%s" % (self.event)
DISTANCE_UNIT_CHOICES = [
("yd", "Yards"),
("m", "Meters"),
]
class Score(models.Model):
person = models.ForeignKey(
"Person",
on_delete=models.CASCADE,
related_name="scores",
)
event_round = models.ForeignKey(
"EventRound",
on_delete=models.CASCADE,
related_name="scores",
)
score = models.PositiveSmallIntegerField()
x_count = models.PositiveSmallIntegerField(blank=True, null=True)
age_division = models.ForeignKey("AgeDivision", on_delete=models.CASCADE)
equipment_class = models.ForeignKey("EquipmentClass", on_delete=models.CASCADE)
gender = models.ForeignKey("Gender", on_delete=models.CASCADE)
distance = models.CharField(max_length=10, blank=True)
distance_unit = models.CharField(max_length=10, choices=DISTANCE_UNIT_CHOICES)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return "%s - %s" % (self.person, self.event_round)