Django. Как заставить ModelChoiceField работать с SingleObjectMixin, FormView и inlineformset_factory?

Итак, я пытался заставить его функционировать так, как планировалось, но, возможно, есть какие-то недоработки, о которых я не знаю.

Задача - показать только связанные варианты в форме с полем выбора.

<

Модель FATURA регистрирует все счета-фактуры и имеет ForeignKey с CONTRATO в отношении один-ко-многим (поэтому один контракт имеет много счетов-фактур)

Модель LANCAMENTO регистрирует записи из договоров, которые позже будут присвоены счету-фактуре в FATURA. Таким образом, LANCAMETNO имеет ForeingKey с CONTRATO в отношении on-to-many (поэтому один контракт имеет много записей в LANCAMENTO). И LANCAMENTO также имеет ForeignKey с FATURA, который по умолчанию равен null, поэтому позже FATURA будет присвоена этой записи в LANCAEMTNO.

Цель состоит в том, чтобы иметь эту логику в форме. Таким образом, когда пользователь обращается к LANCAMETNO для назначения FATURA, он может выбрать только FATURA с таким же id контракта, как у LANCAMETNO.

Я здесь много исследовал, но это все, до чего я могу дойти. Я застрял.

Вот код, если кто-то может направить меня в правильном направлении.

Вот мой код для Models:

from django.db import models
from django.urls import reverse, reverse_lazy

# Create your models here.
class ContratoBlog(models.Model):
    nome_contrato = models.CharField(max_length=100)

    def __str__(self):
        return f"{self.nome_contrato}"
    
    def get_absolute_url(self):
        return reverse('blog:detalhe_contrato', kwargs={'pk' : self.pk})


class FaturaBlog(models.Model):
    datavencimento = models.DateField(null=True, blank=True)
    status = models.CharField(max_length=50, null=True, blank=True)
    id_contrato = models.ForeignKey(ContratoBlog, on_delete=models.CASCADE)

    def __str__(self):
        return f"F.{self.id}.V.{self.datavencimento}"


class LancamentoBlog(models.Model):
    id_contrato = models.ForeignKey(ContratoBlog, on_delete=models.CASCADE)
    datalancamento = models.DateField(null=True, blank=True)
    detalhe = models.CharField(max_length=100, null=True, blank=True)
    id_fatura = models.ForeignKey(FaturaBlog, on_delete=models.CASCADE, blank=True, null=True)
   
    def __str__(self):
        return f"L{self.id}.{self.datalancamento}"

Код для представлений:

Код для форм:

from importlib.metadata import MetadataPathFinder
from django.forms import BaseInlineFormSet
from django import forms
from django.forms.models import inlineformset_factory
from blog.models import ContratoBlog, FaturaBlog, LancamentoBlog



class FooModelChoiceField(forms.Form):
    foo_select = forms.ModelChoiceField(queryset=None)

    def __init__(self, *args, **kwargs):
        super(FooModelChoiceField, self).__init__(*args, **kwargs)
        qs = FaturaBlog.objects.filter(fatura__id_contrato=self.id_contrato)
        self.fields['foo_select'].queryset = qs

ContratoBlogFaturaBlogFormset = inlineformset_factory(
    ContratoBlog, FaturaBlog, 
    fields=('datavencimento','status', 'id_contrato')
    )

ContratoBlogLancamentoBlogFormset = inlineformset_factory(
    ContratoBlog, LancamentoBlog, 
    fields=('datalancamento', 'detalhe', 'id_fatura')
    )

** Код для урлов:**

from django.urls import path, re_path
from blog.views import HomeView, ContratoBlogDetailView, ContratoBlogFaturaBlogEditView, ContratoBlogLancamentoBlogEditView

app_name = 'blog'

urlpatterns = [
    path('', HomeView.as_view(), name='home'),
    #re_path(r'^contrato/(?P<pk>\d+)$', ContratoBlogDetailView.as_view(), name='detalhe_contrato'),
    path('contrato/<int:pk>', ContratoBlogDetailView.as_view(), name='detalhe_contrato'),
    path('contrato/<int:pk>/fatura/edit/', ContratoBlogFaturaBlogEditView.as_view(), name='contrato_fatura_edit'),
    path('contrato/<int:pk>/lancamento/edit/', ContratoBlogLancamentoBlogEditView.as_view(), name='contrato_lancamento_edit'),

Шаблон 1 - Показывает все FATURA и все LANCAMETNO, связанные с CONTRATO:

{% extends 'base.html' %}

{% block content %}
{% include 'blog/contrato_nav.html' %}

<p>
    Contrato ({{contratoblog}}). {{contratoblog.nome_contrato}}.  <BR>
</p>

<p><hr>
    Faturas: <a href="{{ contratoblog.get_absolute_url }}/fatura/edit/">[Editar]</a> <BR>
    <table>
    {% for fatura in fatura_list %}
    <tr>
        <td>[{{ fatura.id }}]</td> <td>Vct. {{ fatura.datavencimento|date:"d M y" }} </td><td>{{ fatura }}</td>  
    </tr>
    {% endfor %}
    </table>
</p>
<p><hr>
    Lan&ccedil;amentos: <a href="{{ contratoblog.get_absolute_url }}/lancamento/edit/">[Editar]</a> <BR>
    <table>
    {% for lancamento in lancamento_list %}
    <tr>
        <td> {{ lancamento.datalancamento|date:"d-M-y" }} </td> <td>{{ lancamento.detalhe }}. </td> <td>{{ lancamento.id_fatura }}</td>
    </tr>
    {% endfor %}
    </table>
</p>
{% endblock %}

Шаблон 2 - показывает все LANCAMETNO, связанные с CONTRATO, но ДОЛЖЕН показывать только FATURA, вместо того, чтобы показывать все записи в fatura.

{% extends 'base.html' %}

{% block content %}

<h2>Lan&ccedil;amentos:</h2>

<hr>
  <form action="" method="post" >
    {% csrf_token %}
    {{ form.non_form_errors }}

    {% for hidden_field in form.hidden_fields %}
      {{ hidden_field.errors }}
      {{ hidden_field }}
      {{ hidden_field.field }}
      {{ hidden_field.help_text }}
    {% endfor %}
     {{ form.management_form }}

    <table>
      <h3>
        {% for hidden_field in form.forms %}
          {{ hidden_field.errors }}
        {% endfor %}
      </h3>
      {% for lancamento_form in form.forms %}
      <h5>
        {% if lancamento_form.instance.id %}
        {% else %}
          {% if form.forms|length > 1 %}
            <!-- Adicionar outro Lan&ccedil;amento -->
          {% else %}
            <!-- Adicionar Lan&ccedil;amento-->
          {% endif %}
        {% endif %}
      </h5>
      <tr><th>Data Lancaamento</th><th>Contrato</th><th>Detalhe</th><th>Fatura</th><th>Deletar</th> </tr>    
        <tr> 
          <td>{{lancamento_form.id}}{{ lancamento_form.datalancamento }}</td> 
          <td>{{ lancamento_form.id_contrato }}</td> 
           <td>{{ lancamento_form.detalhe }}</td> 
           <td>{{ lancamento_form.id_fatura }}</td> 
           <td>{{lancamento_form.DELETE}} Deletar.</td>
        </tr>
      {% endfor %}

    </table>
    <hr>
    <p>
      <button type="submit" value="Update Fatura" >Atualizar Lan&ccedil;amento</button>
      <a href="{{ contrato.get_absolute_url  }}" role="button" >Cancelar</a>
    </p>
  </form>
{% endblock content %}

Цель - показать только связанные варианты в форме с полем выбора.

Я здесь много исследовал, но это все, до чего я могу дойти. Я застрял.

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