django-extra-views将InlineFormSet字段值公开为get_context_data()和forms_valid()方法

时间:2017-08-03 15:19:16

标签: django inline-formset

我想访问InlineFormSet的字段以供消费进入View。

以下是基于https://django-extra-views.readthedocs.io/en/latest/views.html#createwithinlinesview-and-updatewithinlinesview的示例:

from extra_views import InlineFormSet, CreateWithInlinesView,


class ItemsInline(InlineFormSet):
    model = Item


class TagsInline(InlineFormSet):
    model = Tag


class OrderCreateView(CreateWithInlinesView):
    model = Order
    inlines = [ItemsInline, TagsInline]

    def get_success_url(self):
        return self.object.get_absolute_url()

如何在 get_context_data() forms_valid()方法中公开InlineFormSet字段? 警告:以下代码失败!

class OrderCreateView(CreateWithInlinesView):

    [... see above ...]

    def get_context_data(self, **kwargs):
        context = super(OrderCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            context['items'] = ItemsInline(self.request.POST)
            context['tags'] = TagsInline(self.request.POST)
        else:
            context['items'] = ItemsInline()
            context['tags'] = TagsInline()
        return context

    def forms_valid((self, form, inlines):

        [...]    

        return super(OrderCreateView, self).forms_valid(form, inlines)

1 个答案:

答案 0 :(得分:2)

我用这个模型重现了你的例子:

STATUS_CHOICES = (
    (0, 'Placed'),
    (1, 'Charged'),
    (2, 'Shipped'),
    (3, 'Cancelled'),
)

class Order(models.Model):
    name = models.CharField(max_length=255)
    date_created = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    action_on_save = models.BooleanField(default=False)


class Item(models.Model):
    item_name = models.CharField(max_length=255)
    sku = models.CharField(max_length=13)
    price = models.DecimalField(decimal_places=2, max_digits=12, db_index=True)
    order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
    status = models.SmallIntegerField(default=0, choices=STATUS_CHOICES, db_index=True)
    date_placed = models.DateField(default=now, null=True, blank=True)

    def __unicode__(self):
        return '%s (%s)' % (self.item_name, self.sku)


class Tag(models.Model):
    tag_name = models.CharField(max_length=255)
    content_type = models.ForeignKey(ContentType, null=True, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField(null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    def __unicode__(self):
        return self.tag_name

的url:

from django.conf.urls import url
from .views import OrderCreateView, OrderUpdateView

urlpatterns = [
    url(r'^inlines/new/$', OrderCreateView.as_view()),
    url(r'^inlines/(?P<pk>\d+)/$', OrderUpdateView.as_view()),
]

形式:

from django import forms
from .models import Order, Item


class OrderForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ['name']

    def save(self, commit=True):
        instance = super(OrderForm, self).save(commit=commit)
        if commit:
            instance.action_on_save = True
            instance.save()
        return instance


class ItemForm(forms.ModelForm):
    flag = forms.BooleanField(initial=True)

    class Meta:
        model = Item
        fields = ['item_name', 'sku', 'price', 'order', 'status']

查看:

from django.contrib.contenttypes.models import ContentType
from extra_views import InlineFormSet, CreateWithInlinesView, UpdateWithInlinesView
from extra_views.generic import GenericInlineFormSet
from .forms import OrderForm
from .models import Item, Order, Tag


class ItemsInline(InlineFormSet):
    model = Item
    fields = ['item_name', 'sku', 'price', 'order', 'status']


class TagsInline(GenericInlineFormSet):
    model = Tag
    fields = ['tag_name']


class OrderCreateView(CreateWithInlinesView):
    model = Order
    fields = ['name']
    context_object_name = 'order'
    inlines = [ItemsInline, TagsInline]
    template_name = 'extra_views/order_and_items.html'

    def get_success_url(self):
        return '/inlines/%i' % self.object.pk


class OrderUpdateView(UpdateWithInlinesView):
    model = Order
    form_class = OrderForm
    inlines = [ItemsInline, TagsInline]
    template_name = 'extra_views/order_and_items.html'

    def get_success_url(self):
        return ''
  • OrderCreateView中,您无法阅读TagItem条记录 get_context_data方法,因为它们尚未创建。

  • OrderCreateView中,您可以在forms_valid之后阅读所有记录 像往常一样的方法。

  • OrderUpdateView中,您可以阅读中的所有记录 get_context_data方法中的forms_valid方法。

看起来像这样:

class OrderCreateView(CreateWithInlinesView):
    # ... 

    def get_context_data(self, **kwargs):
        data = super(OrderCreateView, self).get_context_data(**kwargs)
        from pprint import pprint
        pprint(self.request.POST)  # there is only post data here
        return data

    def forms_valid(self, form, inlines):
        instance = super(OrderCreateView, self).forms_valid(form, inlines)
        ct = ContentType.objects.get_for_model(self.model)
        print('all items', [item.item_name for item in self.object.items.all()])  # items
        print('all tags', [tag.tag_name for tag in
                           TagsInline.model.objects.filter(content_type=ct, object_id=self.object.id)])  # tags
        return instance

class OrderUpdateView(UpdateWithInlinesView):
    # ... 

    def get_context_data(self, **kwargs):
        context = super(OrderUpdateView, self).get_context_data(**kwargs)
        ct = ContentType.objects.get_for_model(self.model)
        print('all items', [item.item_name for item in self.object.items.all()])  # items
        print('all tags', [tag.tag_name for tag in
                           TagsInline.model.objects.filter(content_type=ct, object_id=self.object.id)])  # tags
        return context