Джанго. Как заставить ModelChoiceField работать с SingleObjectMixin, FormView и inlineformset_factory?

Это не должно быть сложно

Как показать в форме модели Django только связанные записи из Model.B для выбора пользователем. Учитывая, что при условии, что пользователь данных Model.A и Model.C должен выбрать один из возможных вариантов Model.B?

Визуализация проблемы - сквематика

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

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

Модель CONTRATO регистрация всех договоров

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

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

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

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

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

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

      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 django.forms.models import inlineformset_factory
from multiprocessing import context
from urllib import request
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse, reverse_lazy
from blog.forms import  ContratoBlogLancamentoBlogFormset, ContratoBlogFaturaBlogFormset
from blog.models import ContratoBlog, FaturaBlog, LancamentoBlog
from django.views.generic import TemplateView, FormView, CreateView, ListView, DetailView, UpdateView, DeleteView
from django.views.generic.detail import SingleObjectMixin

# Create your views here.
# Views Just Home.
class HomeView(TemplateView):
    template_name = 'blog/home.html'


# Views for Model Contrato.
class ContratoBlogDetailView(DetailView):
    model = ContratoBlog
    template_name = "blog/contratoblog_detail.html"
    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super().get_context_data(**kwargs)
        # Add in a QuerySet Complementary Data
        context['contrato_dados'] = ContratoBlog.objects.get(id=self.object.pk)
        context['fatura_list'] = FaturaBlog.objects.filter(id_contrato=self.object.pk).all()
        context['lancamento_list'] = LancamentoBlog.objects.filter(id_contrato=self.object.pk).all()
        return context

class ContratoBlogFormView():
    pass

#View para Faturas do Contrato
class ContratoBlogFaturaBlogEditView(SingleObjectMixin, FormView):

    model = ContratoBlog
    template_name = 'blog/contrato_fatura_edit.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['fatura_list'] = FaturaBlog.objects.filter(id_contrato=self.object.pk).all()
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=ContratoBlog.objects.all())
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=ContratoBlog.objects.all())
        return super().post(request, *args, **kwargs)

    def get_form(self, form_class=None):
        return ContratoBlogFaturaBlogFormset(**self.get_form_kwargs(), instance=self.object)

    def form_valid(self, form):
        form.save()
        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse('blog:detalhe_contrato', kwargs={'pk': self.object.pk})
    



#---------------------------------
#View para Lancamentos do Contrato
class ContratoBlogLancamentoBlogEditView(SingleObjectMixin, FormView):

    model = ContratoBlog
    template_name = 'blog/contrato_lancamento_edit.html'

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=ContratoBlog.objects.all())
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=ContratoBlog.objects.all())
        return super().post(request, *args, **kwargs)

    def get_form(self, form_class=None):
        return ContratoBlogLancamentoBlogFormset(**self.get_form_kwargs(), instance=self.object)

    def form_valid(self, form):
        form.save()
        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        return reverse('blog:detalhe_contrato', kwargs={'pk': self.object.pk})

Код для форм:

      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')
    )

** Код для URL: **

      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 вместо отображения всех записей в фатуре.

      {% 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 %}

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

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

0 ответов

Другие вопросы по тегам