背景: SellingItem と SellingItemImages の 2 つのモデルがあります。SellingItemImages には、複数のファイルを取得できるカスタム FileField があります。1 つの要素 (enctype="multipart/form-data") の下に 2 つのフォーム (itemform と imageform) を配置することで、ユーザーが複数の画像をアップロードできるようにしました。ここで、クライアント側の画像の最適化とより良い UI を組み込みたいと考えています。filepond を試してみましたが、いくつかの課題に直面しています。この投稿を整理しました
- filepond なしで django コードを表示する
- filepond what でコードを表示する
- これまでにfilepondで達成しました
- 次に何をすべきかについての質問
** 1) filepond なしの django コード。** models.py
# models.py
class SellingItem(models.Model):
seller = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
description = models.CharField(max_length= 500, null=True, blank=True)
price = models.IntegerField(default=0)
class SellingItemImages(models.Model):
sellingitem = models.ForeignKey(SellingItem, default = None, on_delete=models.CASCADE, related_name='images')
image = ContentTypeRestrictedFileField(content_types=['image/png', 'image/jpeg','image/jpg'],blank=True,
max_upload_size=5242880)
#ContentTypeRestrictedFileField is a custom FileField.
ここにforms.pyがあります
class SellingItemForm(forms.ModelForm):
class Meta:
model = SellingItem
fields = ('name', 'description', 'price')
class SellingItemImagesForm(forms.ModelForm):
class Meta:
model = SellingItemImages
fields= ('image',)
widgets = {
'image': forms.FileInput(attrs={'multiple':True,}),
}
これがviews.pyです
@login_required
def post_newitem(request):
if request.method == 'POST':
itemform = SellingItemForm(request.POST)
imageform = SellingItemImagesForm(request.POST, request.FILES)
if '_cancel' in request.POST:
itemform = SellingItemForm()
imageform = SellingItemImagesForm()
return render(request, 'market/post_newitem.html',
{'itemform': itemform, 'imageform': imageform})
else:
if '_publish' in request.POST:
print('hit publish')
if itemform.is_valid() and imageform.is_valid():
print('two forms are valid')
sellingitem = itemform.save(commit=False)
sellingitem.seller = request.user
sellingitem.published_date = timezone.now()
sellingitem.save()
files = request.FILES.getlist('image')
for f in files:
photo = SellingItemImages(sellingitem=sellingitem, image=f)
photo.save()
return redirect('market_home')
else:
print(itemform.errors, imageform.errors)
else:
itemform = SellingItemForm()
imageform = SellingItemImagesForm(request.POST)
return render(request, 'market/post_newitem.html',
{'itemform': itemform, 'imageform': imageform})
ここにテンプレート post_newitem.html があります。ここでは、1 つの要素の下に 2 つのフォームを配置します。
{% extends 'market/marketbase.html' %}
{% block content %}
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in itemform.hidden_fields %}
{{ hidden }}
{% endfor %}
{% load widget_tweaks %}
<table>
<tr>
<td>{{ itemform.name |add_class:"name_form_field"}}</td>
</tr>
<tr>
<td>{{ itemform.description |add_class:"description_form_field" }}</td>
</tr>
<tr>
<td>{{ itemform.price |add_class:"price_form_field" }}</td>
</tr>
{% for hidden in imageform.hidden_fields %}
{{ hidden }}
{% endfor %}
<tr>
<td>
{{ imageform.image |add_class:"image_form_field" }}
</td>
</tr>
</table>
<input class='edit-delete-buttons' type="submit" name="_publish">
<input class='edit-delete-buttons' type="submit" name="_cancel">
</form>
{% endblock %}
上記のコードは、ユーザーが複数の画像をアップロードできるようにするために機能します。前述のように、より優れた UI とクライアント側の画像の最適化を実現するために、この素敵な JavaScript ライブラリである filepond に目を向けました。
2) filepond を使用したコード
<script>
document.addEventListener('DOMContentLoaded', function() {
// Create FilePond object
const inputElement = document.querySelector('input[type="file"]');
const pond = FilePond.create(inputElement, {
// track addfile event
onaddfile: (err, fileItem) => {
console.log(err, fileItem.getMetadata('resize'));
},
// to see whether all files are processed
onprocessfiles: () => {
console.log('process finished for all files');
},
// show when a file is reverted
onprocessfilerevert: (fileItem) => {
console.log(fileItem + 'is reverted');
},
});
});
FilePond.registerPlugin(
FilePondPluginImagePreview,
FilePondPluginImageCrop,
FilePondPluginImageTransform,
FilePondPluginFileValidateType,
FilePondPluginImageResize);
var csrf_token="{{ csrf_token }}";
FilePond.setOptions({
imagePreviewHeight: 100,
allowMultiple: true,
imageCropAspectRatio: 1,
imageResizeTargetWidth: 256,
imageResizeMode: 'contain',
imageTransformOutputQuality: 80,
maxFiles: 4,
server: {
// url, none, because endpoints located on the same server
process: {
headers: {"X-CSRFToken":csrf_token,},
url: '/media/',
method: 'POST',
},
revert: {
headers: {
"X-CSRFToken":csrf_token,
},
url: '/media/',
method: 'DELETE',
},
fetch: null,
load: null,
}
});
</script>
3) これまでに filepond で達成したこと
上記のコードで、できました。a. filepond ドロップ ドラッグ エリアを表示します。画像プレビューを表示 c.次の画像に示すように、アップロードが完了したことを示す filepond d. Chrome 開発ツール コンソールで、「すべてのファイルのプロセスが終了しました」と表示される
2 つのファイルを選択した後の filepond ドロップ領域を示す画像
4) 次に何をすべきかについての質問
a: サーバー関連:「アップロードが完了しました」と表示された緑色のハイライトはユーザー向けであることを理解しています。これは、必ずしもファイルがサーバーにアップロードされることを意味するわけではありません。
ファイルはサーバーにアップロードされましたか? 私のサーバー構成です。正しい?ファイルが (コンソールを使用して) サーバーにアップロードされているかどうかを知るにはどうすればよいですか?
b: django 関連: ファイルがサーバーにアップロードされたら、これらのファイルを取得して適切な django モデル (私の場合、SellingItemsImages) を指すにはどうすればよいですか?
この投稿に示されているように files=request.FILES.getlist('filepond') を試しましたが、ファイルは空のリストを返しました。これがこのスニペットが機能しないためなのか、それとも最初からファイルをアップロードしていないためなのかはわかりません。
c: django フォーム関連: 背景で述べたように、2 つのフォームがあり、1 つは名前、価格などを含む通常のフォームです。画像をアップロードするための別のもの。filepond がなければ、1 つの post_newitem ビューで 1 つの送信ボタンを使用して両方のフォームを送信していました。filepond では、いくつかのオプションがあると思います。- オプション 2: filepond に (transformplugin を介して) 画像を最適化し、画像とその他のフォーム領域 (名前、価格など) を FormData として送信します。
これら 2 つのオプションの長所と短所、およびこれら 2 つのオプションをどのように進めていくかについて、何らかの情報を得たいと考えています。