【问题标题】:django-extra-views expose InlineFormSet field values into get_context_data() and forms_valid() methodsdjango-extra-views 将 InlineFormSet 字段值公开到 get_context_data() 和 forms_valid() 方法中
【发布时间】:2017-08-03 15:19:15
【问题描述】:

我想访问 InlineFormSet 的字段以便在视图中使用。

这里是一个基于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)

【问题讨论】:

    标签: django inline-formset


    【解决方案1】:

    我用这个模型复制了你的例子:

    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
    

    网址:

    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
    

    【讨论】:

    • 对不起,这似乎不起作用。我尝试添加 inlines_names = ['items', 'tags'] 来直接访问命名变量,因为我不知道如何访问'inline_instance'。你能更明确一点吗?谢谢!
    • 哦,你想从模型中读取数据,而不是 InlineFormSet 字段。我更新了答案,请检查。
    猜你喜欢
    • 2019-08-29
    • 2020-01-09
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多