1

Django を使用して、標準の ImageField を使用してアップロードされた画像のサムネイルを作成し、通常の imagefile フィールドと一緒に別のフィールド 'thumbnail' にテーブルへのパスを追加しています。表示できるように、フォームセットを使用してカスタムテンプレートでイメージフィールドオブジェクトをレンダリングするサムネイルパスにアクセスする方法を考え出しています。

「form=CarImageForm」を inlineformset_factory に追加してから、forms.py を変更する必要があると思いますが、その方法や、このアプローチが正しいかどうかさえもわかりません。わかりやすくするために、以下のコード サンプルにはその試みを含めていません。

私の最終目標は、元の画像にリンクするサムネイル画像を返すことです-すでに Imagefile フィールドを介して表示されています。

前もって感謝します!

テンプレートは次のとおりです。

<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset.forms %}
    {% for field in form %}
        {{ field.label }}: {{ field }}<br>
    {% endfor %}
{% endfor %}
<p><input type="submit" value="Enter"/></p>

フォーム.py:

class CarForm(ModelForm):
    class Meta:
        model = Car
        exclude = ['owner', 'uploaded']

ビュー.py:

# Edit an existing record
@login_required
def edit_existing(request, object_id=False):
    try:
        car = Car.objects.get(pk=object_id)
    except Car.DoesNotExist:    
        raise Http404   
    ImageFormSet = inlineformset_factory(Car, CarImage, extra=1, max_num=1)
    if request.method == 'POST':
        form = forms.CarForm(request.POST, instance=car)
        formset = ImageFormSet(request.POST, request.FILES, instance=car)
        if formset.is_valid() and form.is_valid():
            # Handle form.save() to include user id
            new_car = form.save(commit=False)
            new_car.owner = request.user
            new_car.save()
            # Formset - contains the attached images
            formset.save()  
            return HttpResponseRedirect(new_car.get_absolute_url())
    else:
        form = forms.CarForm(instance=car)
        formset = ImageFormSet(instance=car)
    return render_to_response('edit_existing.html',
        {'form': form, 'formset': formset},
        context_instance=RequestContext(request))

models.py:

class Car(models.Model):
    make = models.CharField(max_length=64)
    model = models.CharField(max_length=64)
    owner = models.ForeignKey(User,editable=False)
    uploaded = models.DateField(default=datetime.date.today,editable=False)

    def get_absolute_url(self):
        return reverse('vehicle_admin.views.car_detail', args=[str(self.id)])

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)

class CarImage(models.Model):
    car = models.ForeignKey(Car)
    imagefile = models.ImageField(upload_to=orig_car_id_folder)
    thumbnail = models.ImageField(upload_to=thumb_car_id_folder, editable=False)

    # PIL tips from 
    # https://snipt.net/danfreak/generate-thumbnails-in-django-with-pil/
    # http://www.mechanicalgirl.com/post/image-resizing-file-uploads-doing-it-easy-way/
    def save(self):
        import os
        from PIL import Image
        from cStringIO import StringIO
        from django.core.files.uploadedfile import SimpleUploadedFile
        THUMBNAIL_SIZE = (75, 75)
        super(CarImage, self).save() # Use the commit=False param here?
        image = Image.open(self.imagefile.path)
        if image.mode not in ('L', 'RGB'):
            image = image.convert('RGB')
        image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
        temp_handle = StringIO()
        image.save(temp_handle, 'png')
        temp_handle.seek(0)
        name_ext = os.path.splitext(os.path.split(self.imagefile.name)[-1])
        suf = SimpleUploadedFile(name_ext[0],
                temp_handle.read(), content_type='image/png')
        self.thumbnail.save(suf.name+'.png', suf, save=False)
        super(CarImage, self).save()
4

2 に答える 2

0

私のdjango-extra-viewsライブラリを試してみたい場合は、次のようにすることができます。

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

from extra_views import UpdateWithInlinesView, InlineFormSet


class CarForm(ModelForm):

    def __init__(self, *args, **kwargs):
        self.user = self.kwargs.pop('user')
        super(CarForm, self).__init__(*args, **kwargs)

    def save(self, commit=True)
        instance = super(CarForm, self).save(commit=False)
        instance.user = self.user

        if commit:
            instance.save()
        return instance

    class Meta:
        model = Car
        exclude = ['owner', 'uploaded']


CarImageInline(InlineFormSet):
    model = CarImage
    extra = 1
    max_num = 1


UpdateCarView(UpdateWithInlinesView):
    pk_url_kwarg = 'object_id'
    inlines = [CarImageInline]
    template_name = 'edit_existing.html'
    form_class = CarForm

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(UpdateCarView, self).dispatch(*args, **kwargs)

    def get_form_kwargs(self):
        kwargs = super(UpdateCarView, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

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

主な違い:

  • フォームはユーザーを車に割り当てる役割を担い、フォームはインスタンス化されたときにユーザーを取得します (get_form_kwargs を参照)。このようにする理由は、クラスベースのビューでは、form_valid (またはこの場合は forms_valid) をオーバーライドするのが少し面倒なので、フォームに何かを入れることを好みます。
  • formsetコンテキストを取得する代わりにinlines、フォームセットのリストである を取得します。これは、技術的には必要な数のインライン フォームセットを持つことができるためです。この場合は 1 つしかありませんが、実質的に Django 管理者の動作と同じです。
  • dispatchデコレータを適用するためのオーバーライドlogin_requiredは扱いにくいですが、幸いなことに、これは mixin に簡単に抽象化できるものです。既製のものについては、 django-bracesを参照してください。
于 2013-01-29T00:41:14.517 に答える
0

これは私の基本的な見落としだと思います。

私の問題は、「サムネイル」フィールドの CarImage モデルで editable=False を設定することでした。これは最初のデータ送信には問題ありませんが、そのフィールドがフォームで自動的に除外されるため、エントリを編集すると問題が発生します。(詳細については、上記のコード スニペットを参照してください。)

次のステップは、add_new ビューのカスタム フォームをセットアップすることです (最初はこのビューを含めませんでしたが、データの最初のアップロードを有効にするために使用していたものです)。

class InitialCarImageForm(ModelForm):
    class Meta:
        model = CarImage
        exclude = ['thumbnail']

正しいアプローチは editable=False を使用することだと思いますが、このアプローチで重大な間違いを犯していない限り、おそらくうまくいくでしょう。

私はこのサイトを初めて使用するので、この方法で質問に答えることがサイトを閉じる正しい方法であるかどうかを教えてください.

于 2013-01-25T13:11:35.433 に答える