ここに埋もれているいくつかの小さな関連する質問がありますが、それらは実際には 1 つの大きな毛むくじゃらのベスト プラクティスの質問を示しています。これは、一度にいくつかのトリッキーなことを行うことになっているため、実装するのが難しい機能です...
- ドラッグ アンド ドロップの複数ファイル アップローダ (Javascript 経由)
- 複数ページのフォーム (1 ページ目: ファイルをアップロードして既存のドキュメント モデルに関連付ける。2 ページ目: ファイル/ドキュメント オブジェクトとメタデータを更新してデータベースに保存する)
...そして、既存のコード サンプルや実装はどこにも見つかりませんでした。(アプローチによっては、テーブルから一掃するか、関連/埋め込み/フォローオンのすべての質問に自動的に回答することができます。) 要するに、この投稿の目的は、次の質問に回答することです。介在する質問/問題?
ファイルをアップロードするために、DjangoでドラッグアンドドロップのJQuery File Uploaderのこの実装を使用しています...
https://github.com/miki725/Django-jQuery-File-Uploader-Integration-demo
上記でリンクしたソリューションでは、もちろんファイル システムにファイルを保存しますが、ファイルのバッチごとにディレクトリを作成し、それらの各ディレクトリに UUID を割り当てることで、アップロード セッションごとにバッチで保存します。ファイルシステム上の一意の名前が付けられた各ディレクトリには、その特定のアップロード セッション中にアップロードされたファイルが含まれます。つまり、どのような種類のデータベース ストレージ メソッドでも、最初に、このソリューションによって各アップロード セッション用に作成されたファイル システム ディレクトリ内のすべてのファイルをばらばらにして繰り返し処理する必要があります。
注: 上記にリンクされている JQuery ソリューションは、アプリ ディレクトリ内のフォーム (forms.py 内) を使用しません。フォームはテンプレートにハードコードされていますが、これはすでに少し残念です...なぜなら、各バッチ内の上記の各ファイルをフォームにバインドする良い方法も見つけなければならないからです。
最も単純な方法は、おそらく最もパフォーマンスの低いソリューションではあると思いますが、2 つのフォームに対して 2 つのビューを作成し、最初のページのビューで各ファイルをデータベースに保存してから、2 番目のページでデータベースを更新することです。これが私が現在転がっている方向です:
テンプレートで...
...uploader javascripts in header...
<form action="{% url my_upload_handler %}" method="POST" enctype="multipart/form-data">
<input type="file" name="files[]" multiple
</form>
ビューで.PY...
def my_upload_handler_0r_form_part_one(request):
# POST (アップロード ハンドラ内。アップロード アクションによってトリガーされるリクエスト)
if request.method == 'POST':
if not ("f" in request.GET.keys()):
...validators and exception handling...
...response_data, which is a dict...
uid = request.POST[u"uid"]
file = request.FILES[u'files[]']
filename = os.path.join(temp_path, str(uuid.uuid4()) + file.name)
destination = open(filename, "wb+")
for chunk in file.chunks():
destination.write(chunk)
destination.close()
response_data = simplejson.dumps([response_data])
response_type = "application/json"
# return the data to the JQuery uploader plugin...
return HttpResponse(response_data, mimetype=response_type)
# GET (同じアップロード ハンドラ内)
else:
return render_to_response('my_first_page_template.html',
{ <---NO 'form':form HERE
'uid': uuid.uuid4(),
},
context_instance = RequestContext(request))
def form_part_two(request):
#here I need to retrieve and update stuff uploaded on first page
return render_to_response('my_second_page_template.html',
{},
context_instance = RequestContext(request))
最初のページのこのビューは、JQuery アップローダーを活用しています。これは、セッションごとの複数ファイルのアップロードに最適で、本来の機能を果たします。ただし、上で示唆したように、アップロード ハンドラとしてのビューは、2 ページ フォームにする必要があるものの最初のページにすぎません。2 ページ目では、エンド ユーザーはアップロードされた各ファイルを取得し、1 ページ目でアップロードしたばかりのファイルに追加データを添付して、データベースに再度保存する必要があります。
フォーム ウィザードやジェネリック クラス ベースのビューなど、さまざまなソリューションを使用して、これを 2 部構成のフォームとして機能させようとしました。以下の例では、主にセッションを介してデータの永続性を有効にしています。これらのソリューションは、かなり厄介なものになります。
要約すると、私はする必要があります...
- 一意に識別されたバッチで複数のファイルをアップロードします (ドラッグ アンド ドロップを使用)。
- アップロードされたファイルの各バッチを分解して繰り返します
- バッチ内の各ファイルをフォームにバインドし、既存のドキュメント モデルに関連付けます
- これらすべてのファイルを一度にデータベースに送信/保存します
- 新しい可能性があるフォームの次のページ/テンプレートで、これらの各ファイルを取得します
- 各ファイルのメタデータを更新する
- これらのファイルをすべて一度にデータベースに再送信/保存します
したがって...上記のすべてが単純なファイルのアップロードの複雑さをどのように複雑にし、次のような関連する質問を含めることで、機能を提供する複雑さを増すかを見ることができます。
forms.py : 各ファイルをフォームにバインドする最善の方法
models.py : 各ファイルを既存のドキュメント モデルに関連付ける方法
views.pyの最初のページで、Postgres の既存のドキュメント モデルに従って各ファイルを保存する方法。2 ページ目の各ドキュメントを更新して保存する
...そして、繰り返しになりますが、フォーム ウィザードやクラス ベースのビューを使用せずに、これらすべてを実行したいと考えています。(特に、このユース ケースの CBV は、私には少しわかりません。) 言い換えれば、可能な限り最も防弾で読みやすく/理解しやすいソリューションにつながるアドバイスを探しています。データベースに複数のヒットが発生する場合は、それで問題ありません。(ファイルをデータベースに保存することがベスト プラクティスに反すると思われる場合は、別の投稿を参照してください:データベースにファイル コンテンツを保存する
2 つのフォーム用に個別のビューを作成し、標準のアップロード フォームをサブクラス化することはできますか?
forms.py で...
class FileUploadForm(forms.Form):
files = forms.FileField(widget=forms.ClearableFileInput(attrs={'name':'files[]', 'multiple':'multiple'}))
#how to iterate over files in list or batch of files here...?
file = forms.FileField()
file = forms.FileField()
def clean_file(self):
data = self.cleaned_data["file"]
# read, parse, and create `data_dict` from file...
# subclass pre-existing UploadModelForm
**form = UploadModelForm(data_dict)**
if form.is_valid():
self.instance = form.save(commit=False)
else:
raise forms.ValidationError
return data
...そして、上記の以前のアップロードハンドラーを次のようにリファクタリングします...
views.py で、現在のアップロード ハンドラを次のように置き換えます...
def view_for_form_one(request):
...
# the aforementioned upload handler logic, plus...
...
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
else:
# display errors
pass
...
def view_for_form_two(request):
# update and commit all data here
...?