Django RelatedManager: получить текущее значение выбранного элемента - PullRequest
1 голос
/ 27 мая 2020

У меня есть модель со значением duration и объектом durations, который, в свою очередь, имеет несколько значений duration_mins внутри. root -уровень duration действует как резерв, если объект durations пуст.

Ответ конечной точки выглядит примерно так:

{
    "id": 1,
    "name": "Track Name X",
    "duration": 10,
    "durations": [
        {
            "id": 218,
            "duration_mins": 10
        },
        {
            "id": 219,
            "duration_mins": 15
        },
        {
            "id": 220,
            "duration_mins": 20
        }
    ]
}

Основная идея состоит в том, чтобы иметь сумма «Минут прослушивания». Прямо сейчас мы делаем

self.total_sec += single.duration

, который правильно добавляет запасной вариант, продолжительность root -уровня. Я хочу добавить текущее значение продолжительности (отправленное клиентом). ie: если пользователь выбрал 20 мин. Продолжительность.

Я пробовал следующее:

if single.durations:
    self.total_sec += single.durations.get().duration_mins
else:
    self.total_sec += single.duration

Что явно не работает, но объясняет, чего я пытаюсь достичь sh. Ошибка, которую я получаю:

AttributeError: 'RelatedManager' object has no attribute 'duration_in_minutes'

или, если я добавлю .get ()

[...]MultipleObjectsReturned: get() returned more than one Duration -- it returned 3!

Может кто-нибудь подскажите, как получить текущую выбранную длительность? (Предполагая, что клиент отправляет соответствующий идентификатор продолжительности)

Спасибо!

models.py (сокращенно)

class Duration(models.Model):
    single = models.ForeignKey('Single', on_delete=models.CASCADE, related_name='durations')
    duration_mins = models.PositiveSmallIntegerField(help_text='Single duration in minutes')

class Single(ActiveAndTimeRestrictedMixin):
    name = models.CharField(max_length=128)
    duration = models.PositiveSmallIntegerField(help_text='Single duration in minutes')

class Stat(models.Model):
    user = models.OneToOneField(
        'users.CustomUser', related_name='stats', on_delete=models.CASCADE)
    total_seconds = models.PositiveIntegerField(
        default=0, blank=True, help_text='Total seconds meditated')

    def reset(self):
        self.total_seconds = 0
        self.save()

    def update_after_finish(self, single, save=True):
        self.total_seconds += single.duration
        ...

serializers.py (сокращенно)

class SingleSerializer(serializers.ModelSerializer):
    durations = serializers.SerializerMethodField()

    class Meta:
        model = Single
        fields = ('id', 'name', 'duration', 'durations')

    def get_durations(self, obj):
        durations = obj.durations.all().order_by('duration_mins')
        return DurationSerializer(durations, many=True).data

1 Ответ

0 голосов
/ 27 мая 2020

Вы можете получить общее количество секунд продолжительности, используя агрегирование для моделей django.

from django.db.models import Sum
from django.db.models.functions import Coalesce
...
total = single.durations.filter(id=received_id).aggregate(total=Coalesce(Sum('duration_mins'), 0)))['total']
self.total_secs += total or single.duration
...