私はこのようなモデルを持っています(簡略化):
class TrainingMoment(models.Model):
date = models.DateField()
# Moment of the day, 2 is afternoon for example
moment_nr = models.IntegerField()
is_group_moment = models.BooleanField()
特定の日付と moment_nr には、2 つの行が存在する可能性があります。1is_group_moment=False
つと 1 つis_group_moment=True
。の重複のすべてについてTrainingMoment.objects.filter(date__range=(start_date,end_date))
、 で行を除外したいis_group_moment = True
。
is_group_moment=True
で行を除外したいことに注意してくださいis_group_moment=False
。
最初に重複行を取得するために annotate() を group_by() と一緒に使用しようとしましたが、必要に応じて両方ではなく、各重複行セットの 1 つだけが med に与えられます。
例えば:
╔════════════════════════════════════════╗
║ date moment_nr is_group_moment ║
╠════════════════════════════════════════╣
║ 2013-10-01 1 True ║
║ 2013-10-02 1 True ║
║ 2013-10-02 1 False ║
║ 2013-10-03 1 False ║
║ 2013-10-03 2 False ║
║ 2013-10-04 2 True ║
║ 2013-10-04 2 False ║
║ 2013-10-01 1 True ║
╚════════════════════════════════════════╝
次のようにする必要があります。
╔═════════════════════════════════════════╗
║ date moment_nr is_group_moment ║
╠═════════════════════════════════════════╣
║ 2013-10-01 1 True ║
║ 2013-10-02 1 False ║
║ 2013-10-03 1 False ║
║ 2013-10-03 2 False ║
║ 2013-10-04 2 False ║
║ 2013-10-01 1 True ║
╚═════════════════════════════════════════╝
上記のクエリセットを使用して週の正しい合計を取得するトレーニング時間を格納する別のモデル Activity があります。
class Activity(models.Model):
activitytype = models.ForeignKey(ActivityType)
trainingmoment = models.ForeignKey(TrainingMoment)
# Time in minutes
time = models.IntegerField()
私が達成したいことの要約:
# 1. Get training moments for a given period, for example a week (no problem here)
tms_for_summing = TrainingMoment.objects.filter(date__range=(start_date,end_date))
# 2. Filter out duplicates in the way described above
# 3. Use the resulting queryset (tms_for_summing) to sum activity
summed_activity = Activity.objects.filter(trainingmoment__in = tms_for_summing)
編集 ここでは、私のデータベース設計について疑問に思っている人のために、いくつかの追加説明を行います。
これは、おそらくご存知のとおり、トレーニング ログ アプリです。私の質問の場合、実現したいページは企画ページです。すべてのトレーニングの瞬間は、計画されたトレーニングの瞬間です。個々のアスリートは、自分のトレーニングを計画できます。また、トレーナーはアスリートのグループのトレーニングを同時に計画できます。これがグループ モーメントになります (is_groupmoment = True のトレーニング モーメントと、特定のグループにリンクする多対多フィールド)。アスリートがグループモーメントもあるモーメント番号と日付にグループモーメントを計画している場合、彼自身のモーメントはこのモーメントを上書きする必要があります。
実用的で非常に単純化された例
私には次の個々の瞬間があります: 日、瞬間nr 月曜日 1 火曜日 1
そして次のグループモーメント: Day, Momentr 火曜日 1 水曜日 1
瞬間とこれらの瞬間に関連する活動の合計を示す表では、月曜日と火曜日の個々の瞬間だけでなく、グループの瞬間を上書きする個人の瞬間がないため、水曜日のグループの瞬間も表示したいと思います。グループの瞬間と個々の瞬間の両方が同じ日付の瞬間にあるかどうかを確認しながら、瞬間を1つずつ合計することにより、純粋なPythonコードを使用してビューで合計を行うことができますが、これは本当に醜く遅い方法ですそれは、特に 1 年を合計する場合に顕著です。
私が試したこと
私はこれを試しました:
training_moments = TrainingMoment.objects.filter(date__range=('2013-08-19','2013-10-28'))
moments_to_exclude = training_moments.annotate(num_dates=Count('date'), num_momentnrs=Count('momentnr')).filter(num_dates__gt= 1, num_momentnrs__gt=1)
これは近いです。これにより、「タイムスロット」ごとに1つの瞬間が得られます(瞬間番号と日付は、グループの瞬間と個々の瞬間で同じです)。問題は、両方の「衝突」の瞬間を取得する必要があることです。次に、結果のクエリ セットからグループ モーメントを除外し、最終的にアプリでトレーニング モーメントを合計するときに除外するモーメントを取得できます。
moments_to_exclude = moments_to_exclude.exclude(is_group_moment=True)
desired_result = training_moments.exclude(pk__in=moments_to_exclude)