【问题标题】:Issue saving image in Django using CreateView and inlineformset_factory使用 CreateView 和 inlineformset_factory 在 Django 中保存图像问题
【发布时间】:2014-03-13 04:59:42
【问题描述】:

使用基于类的通用 CreateView 我正在尝试通过 ClearableFileInput 小部件上传图像,这是 inlineformset_factory 使用的默认小部件,但这失败了。

在我看来,form.save() 工作得很好,它似乎是 specimage_form.save() 失败了。如果我在提交过程中打印 self.request.FILES ,它看起来好像所选文件在内存中 - 但是在 SpecImage save() 函数中添加了一个打印语句,很明显这个函数永远不会被调用。

可以使用管理站点使用内联上传图像,在这种情况下我会看到打印语句..

这是我的代码 - 感谢任何建议或指导。提前谢谢..

models.py

class Spec(models.Model):
    car = models.ForeignKey('vehicles_dvla_listpoint.AutoLookup')
    owner = models.ForeignKey(User)
    uploaded = models.DateField(default=date.today, editable=False)

    def get_absolute_url(self):
        return reverse('car_create')

    def __unicode__(self):
        return "{0}".format(self.car)

class SpecImage(models.Model):
    def orig_car_id_folder(instance, filename):
        return 'uploads/images/orig/{0}/{1}'.format(instance.car_id, filename)
    def thumb_car_id_folder(instance, filename):
        return 'uploads/images/thumb/{0}/{1}'.format(instance.car_id, filename)

    car = models.ForeignKey(Spec)

    orig_image = models.ImageField(
        upload_to=orig_car_id_folder, 
        verbose_name='Upload Image',
    )

    thumbnail = models.ImageField(
        upload_to=thumb_car_id_folder,
        null=True,
        blank=True,
    )

    def save(self, force_update=False, force_insert=False): 
        print "here ...." # << Don't see this where submitting outside of the admin
        import os
        from PIL import Image
        from cStringIO import StringIO
        from django.core.files.uploadedfile import SimpleUploadedFile
        # Set thumbnail size
        THUMBNAIL_SIZE = (75, 75)
        # Process original image using PIL
        image = Image.open(self.orig_image)           
        # Convert to RGB if necessary
        if image.mode not in ('L', 'RGB'):
            image = image.convert('RGB')
        # PIL already has constraint proportions
        # Also use Image.ANTIALIAS to make the image look better
        image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
        # Save thumbnail - to disk?
        temp_handle = StringIO()
        image.save(temp_handle, 'png')
        temp_handle.seek(0)
        # Save to thumbnail field (in table)
        # Prepare file name - just name & strip .ext 
        name_ext = os.path.splitext(os.path.split(self.orig_image.name)[-1])
        suf = SimpleUploadedFile(name_ext[0],
                temp_handle.read(), content_type='image/png')
        self.thumbnail.save(suf.name+'.png', suf, save=False)
        # Save this photo instance (again)
        super(SpecImage, self).save()

urls.py

urlpatterns = patterns('',
    url(r'^add/$', CarCreate.as_view(), name='car_create'),
    url(r'^thanks/$', TemplateView.as_view(template_name='thanks.html')),
)

forms.py

import autocomplete_light
from django.forms.models import inlineformset_factory

from .models import Spec, SpecImage

class SpecForm(autocomplete_light.ModelForm):
    class Meta:
        model = Spec

SpecImageFormSet = inlineformset_factory(Spec, SpecImage, extra=1)

views.py

class CarCreate(CreateView):
    template_name = 'spec_form_inlines.html'
    model = Spec
    form_class = SpecForm
    success_url = '/car/thanks/'

    def form_valid(self, form):
        context = self.get_context_data()
        specimage_form = context['specimage_form']
        if specimage_form.is_valid():
            self.object = form.save()
            specimage_form.instance = self.object
#            specimage_form.instance = self.request.FILES
            specimage_form.save()
            return HttpResponseRedirect('/car/thanks/')
        else:
            return self.render_to_response(self.get_context_data(form=form))

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def get_context_data(self, **kwargs):
        context = super(CarCreate, self).get_context_data(**kwargs)
        if self.request.POST:
            context['specimage_form'] = SpecImageFormSet(self.request.POST)
        else:
            context['specimage_form'] = SpecImageFormSet()
    return context

spec_form_inlines.html

<html>
<body>

<h1>Add Book</h1>

<form enctype="multipart/form-data" method="post" action="">
    {% csrf_token %}

    {{ form.as_p }}

    {{ specimage_form.management_form }}
    {% for form in specimage_form.forms %}
        {{ form.as_p }}
    {% endfor %}

    <input type="submit" value="Add Car" class="submit"/>
</form>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.js" type="text/javascript"></script>
{% include 'autocomplete_light/static.html' %}

</body>
</html>

我对基于类的视图非常陌生,上次我设法通过函数视图实现了这一点,但它们似乎是一种旧的做事方式,有时它不是一个明显的过渡。非常欢迎任何建议或指导。

谢谢。

【问题讨论】:

    标签: django django-class-based-views django-generic-views


    【解决方案1】:

    所以这似乎是一个足够简单的解决方法,但我花了一段时间通过检查在线示例和阅读 Django 文档来解决问题,所以我把它留在这里而不是把问题记下来。

    我的初始代码基于this blog post

    除非我遗漏了什么,尽管这是一个包含图像上传的示例,但它似乎缺少的是对 request.FILES 的引用来绑定图像。因此,现在看来可行的简单更改是更改此行:

    if self.request.POST:
      context['specimage_form'] = SpecImageFormSet(self.request.POST)
    

    到这里

    if self.request.POST:
      context['specimage_form'] = SpecImageFormSet(self.request.POST, self.request.FILES)
    

    可以找到使用 render_to_response 而不是设置上下文元素的另一个示例here

    同样,对于具有 ImageField 的表单集,需要额外引用 request.FILES。

    这两种方法似乎都可以正常工作。

    有关将图像绑定到表单的更多信息,请参见Django Docs

    【讨论】:

    • 近一周没有 cmets 所以我接受这个作为答案。
    猜你喜欢
    • 1970-01-01
    • 2019-11-26
    • 2017-10-24
    • 1970-01-01
    • 2015-08-08
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多