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_, но сохраняя все филы внешнего ключа после фильтра? Спасибо!

Вернуться на верх