Django генерация inlineformset на основе моделей, не определенных в inlineformset_factory - PullRequest
0 голосов
/ 20 апреля 2020

Мне удалось частично отойти от поведения, к которому я стремлюсь. У меня есть два вопроса:

  1. Мой подход кажется довольно запутанным, и мне интересно, есть ли лучший способ
  2. В текущем подходе мне удается получить основы c Однако я ищу поведение, если форма недействительна. Я теряю начальные значения в inlineformset приема, когда форма повторно отображается

У меня есть четыре модели, которые связаны друг с другом в процессе покупки :

  1. Order
  2. OrderLine
  3. Reception
  4. ReceptionLine

Заказ на покупку и его дочерний заказ на покупку линии генерируются с помощью inlineformset - это работает просто отлично. Когда дело доходит до записи приема, я пытаюсь получить набор inlineform приема, чтобы сгенерировать начальные строки приема на основе того, что было введено в качестве строк заказа на покупку. Статус приема записывается в строке заказа на покупку с помощью сигналов.

models.py

class Order(models.Model):
    requestor = models.CharField(max_length=10)

class OrderLine(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    item = models.CharField(max_length=30)
    quantity_ordered = models.PositiveIntegerField()
    quantity_received = models.PositiveIntegerField(blank=True, default=0)
    quantity_remaining = models.PositiveIntegerField(blank=True, default=0)

class Reception(models.Model):
    order = models.ForeignKey('purchase.Order', on_delete=models.SET_NULL, null=True)
    receiver = models.CharField(max_length=10)

class ReceptionLine(models.Model):
    reception = models.ForeignKey(Reception, on_delete=models.CASCADE)
    order_line = models.ForeignKey('purchase.OrderLine', on_delete=models.SET_NULL, null=True)
    quantity = models.PositiveIntegerField()

views.py

class Create(generic.CreateView):
model = receive_models.Reception
form_class = receive_forms.ReceptionForm
template_name = 'generic/edit.html'

def get_initial(self):
    order = get_object_or_404(purchase_models.Order, pk=self.kwargs['pk'])

    initial = super(Create, self).get_initial()
    initial['order'] = order

    return initial

def get(self, request, *args, **kwargs):

    order = get_object_or_404(purchase_models.Order, pk=self.kwargs['pk'])
    order_line = order.orderline_set.values(
        order_line=F('id'),
        item_name=F('item'),
        qty_ordered=F('quantity_ordered'),
        qty_received=F('quantity_received'),
        qty_remaining=F('quantity_remaining')
    )

    order_line_count = order_line.count()

    self.object = None
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    formset = receive_forms.ReceptionLineFormSet(queryset=purchase_models.OrderLine.objects.none(), initial=order_line)

    return self.render_to_response(self.get_context_data(form=form, formset=formset))

def post(self, request, *args, **kwargs):

    self.object = None
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    formset = receive_forms.ReceptionLineFormSet(self.request.POST, instance=form.instance)

    if form.is_valid() and formset.is_valid():
        return self.is_valid(form, formset)

    else:
        return self.is_invalid(form, formset)

def is_valid(self, form, formset):

    self.object = form.save(commit=False)
    self.object.created_by = self.request.user

    with transaction.atomic():
        self.object.save()
        formset.save()

    return super().form_valid(form)

def is_invalid(self, form, formset):

    return self.render_to_response(self.get_context_data(form=form, formset=formset))

forms.py

class ReceptionForm(forms.ModelForm):
class Meta:
    model = models.Reception
    fields = ['receiver', 'order']

def __init__(self, *args, **kwargs):
    super(ReceptionForm, self).__init__(*args, **kwargs)

    self.fields['order'].disabled = True

    self.helper = FormHelper()
    self.helper.form_tag = False


class ReceptionLineForm(forms.ModelForm):
    item_name = forms.CharField(disabled=True, required=False)
    qty_ordered = forms.IntegerField(disabled=True, required=False)
    qty_received = forms.IntegerField(disabled=True, required=False)
    qty_remaining = forms.IntegerField(disabled=True, required=False)

    class Meta:
        model = models.ReceptionLine
        fields = ['order_line', 'item_name', 'qty_ordered', 'qty_received', 'qty_remaining', 'quantity']
        widgets = {'order_line': forms.HiddenInput()}

    def __init__(self, *args, **kwargs):
        super(ReceptionLineForm, self).__init__(*args, **kwargs)

        self.fields['order_line'].disabled = False
        self.fields['order_line'].required = False

        self.helper = FormHelper()
        self.helper.template = 'bootstrap4/layout/table_inline_formset.html'
        self.helper.form_tag = False


ReceptionLineFormSet = forms.inlineformset_factory(
    parent_model=models.Reception,
    model=models.ReceptionLine,
    form=ReceptionLineForm,
    extra=2,
    min_num=1
)

signal.py

@receiver(pre_save, sender = ReceptionLine)
def update_orderline(sender, instance, **kwargs):

    orderline = OrderLine.objects.get(id=instance.order_line.id)
    orderline.quantity_received += instance.quantity
    orderline.quantity_remaining = orderline.quantity_ordered - orderline.quantity_received
    orderline.save()
...