Django - Как сравнить разные модели с одинаковым внешним ключом
Я действительно застрял в том, как это сделать, и буду признателен за помощь. У меня есть три модели, две из них имеют одно и то же поле внешнего ключа:
class AccountsPlan (models.Model):
code = models.CharField(max_length=7, unique=True,)
name = models.CharField(max_length=100, unique=True,)
class Planning (models.Model):
accountplan = models.ForeignKey(AccountsPlan, on_delete=models.PROTECT)
month = models.DateField()
amount = models.DecimalField(max_digits=14, decimal_places=2,)
class Revenue (models.Model):
accountplan = models.ForeignKey(AccountsPlan, on_delete=models.PROTECT)
receipt_date = models.DateField()
amount = models.DecimalField(max_digits=14, decimal_places=2,)
И у меня есть представление, которое аннотирует сумму для каждой модели по имени внешнего ключа с формой, которая фильтрует по дате:
def proj_planning(request):
form = ProjectionFilterForm(request.POST or None)
# some definitions for the form
planned = Planning.objects.values('accountplan__name').annotate(Sum('amount')).order_by('accountplan__code').filter(
month__range=[start_date, planned_end_date])
done = Revenue.objects.values('accountplan__name').annotate(Sum('amount')).filter(
receipt_date__range=[start_date, end_date],).order_by('accountplan__code')
if request.method == 'POST':
planned = Planning.objects.values('accountplan__name').annotate(Sum('amount')).order_by(
'accountplan__code').filter(month__range=[start_date, planned_end_date],
accountplan__name__icontains=form['accountplan'].value())
done = Revenue.objects.values('accountplan__name').annotate(
Sum('amount')).filter(receipt_date__range=[start_date, end_date],
accountplan__name__icontains=form['accountplan'].value())
comp_zippedlist = zip(planned, done)
return render(request, 'confi/pages/planning/proj_planning.html', context={
'form': form,
'list': comp_zippedlist,
})
Код вроде как работает (не выдает никаких ошибок), но дело в том, что у меня никогда не будет точного количества данных для каждой модели.
Например: если у меня есть 6 различных записей в модели Planning, но только 4 записи в модели Revenues, то в списке zip будут показаны только 4 записи в модели Revenues, а не 2 другие записи в модели Planning, что имеет смысл.
Но что мне нужно, так это показать все 6 записей из модели Planning с соответствующими 4 записями из модели Revenue, а остальные 2 - пустые или что-то вроде этого. В конечном итоге, мне нужно будет сравнить эти два значения и показать некий статус, основанный на двух значениях поля amount, поэтому мне нужно показать их все.
Результат, который я ожидаю, будет примерно таким:
Accountplan | Planned | Done
__________________________________
Accountplan A | 500 | 250
Accountplan B | 1000 | 860
Accountplan C | 800 | None
Accountplan D | 150 | 350
Accountplan E | 300 | None
Accountplan F | 700 | 900
Я пытался использовать prefetch_relatedдля этого, используя следующий код:
done = AccountsPlan.objects.prefetch_related('revenue_set').values(
'name').annotate(Sum('revenue__amount')).order_by('code')
И хотя он показывает именно то, что я хочу, если я применю фильтр в поле receipt_date модели Revenue, это даст тот же результат, что и раньше, ведь опять же, есть смысл.
Я думал просмотреть все записи о доходах без плана счетов и применить к ним временное значение 0, но план счетов является обязательным, поэтому эта идея не имеет смысла.
Я также посмотрел на наследование нескольких таблиц, но поскольку связь с дочерними моделями один-к-одному, она не применима в этом случае (если только я не понял что-то неправильно).
Есть ли способ получить поведение, описанное и возможное с помощью кода, связанного с prefetch_, но сохраняя все филы внешнего ключа после фильтра? Спасибо!