質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3551閲覧

Djangoで静的ファイルをダウンロードする方法について

donadona

総合スコア19

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/12/02 00:34

編集2018/12/02 02:58

DjangoでWebアプリケーションを作っております。
(Python3.6 Django2.0)

Google Earthで表示できるkmzファイル(バイナリ)を作成して、サーバー上のフォルダに保存するところまではできました。
最後に、ユーザにダウンロードしてもらうようにしたいのですが、ダウンロードのやり方が分かりません。

ダウンロードさせたいファイルは以下の場所にあります。
myproject/myapp/archive/result.kmz

ちなみに、modelクラスは

class Mymodel(model.models): ... file_path = models.CharField()

でして、文字列としてfile_path に result.kmz(ダウンロードするファイル)の絶対パスを保持しています(ファイルそのものではありません)

HTMLに直接

<a href="{{object.file_path}}" download="{{object.file_path}}" class="btn">ダウンロード</a>

ではNG(not allowed to load local resource)でした。

そこで、ダウンロード用のViewクラスを作成しようとしていますが、どのようにしていいかよく分かりませんでした。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gh640

2018/12/02 02:21 編集

(少し誘導的な質問ですが)「絶対パスを保持しています」の「絶対パス」というのは、 a) サーバーのファイルシステム上のパスですか?それとも b) 外部から http(s) でアクセスできる URL ですか?これら 2 つは別物なので区別する必要があります。私のこの質問の意味がちょっとわからないなという場合は具体的な例(実際に描画された html 等)をお示しいただければと思います。追記: `(not allowed to load local resource)` というメッセージからはおそらく a) ではないかと思うのですがかがでしょう。
gh640

2018/12/02 02:25

もうひとつ質問です。「ダウンロードさせたいファイル」というのは、 c) その URL を知っていれば誰でもダウンロードできてよいものですか?それとも、 d) 特定のユーザだけがダウンロードできる形にされたいですか? e) あるいはもっと別の形を想定されていますか?
gh640

2018/12/02 02:27

また、お使いの Python/Django のバージョンと、サーバの種類(≒ Django の動かし方)をご説明された方が、具体的で有益な回答がもらえやすくなると思います :)
donadona

2018/12/02 02:30

回答頂きましてありがとうございます。おっしゃるように、URLではなくサーバー上のパスになっています(os.path.abspath(__file__)で取得して当該ファイルまで引っ張っています)。したがって、今はWindowsで開発中なので、c:\...からとなっています。URLにするのでしょうか?(後ほど試してみます。)
donadona

2018/12/02 02:32

Python3.6 Django2.0です。 ログインしたユーザーが、kmzファイルを作成できるようにしています。ユーザーで識別しているので、ダウンロードリストには、自分が作成したファイルしか見えません。ただ、ダウンロード先は共通のフォルダになっているので、ダイレクトにアクセスされたら、到達できてしまうのかもしれません。
gh640

2018/12/02 02:33

そうなのですね。そうですね、「サーバーのファイルシステム上のパス」と「外部から http でアクセスできる URL 」は別物なので両者は区別する必要があります。そして、 html の `href` には後者を入れる必要があります。
gh640

2018/12/02 02:39

アクセスについてもご回答いただきありがとうございます。ご察しのとおり、各ファイルが特定のユーザにひもづいていてそのユーザだけがダウンロードできるべきなのであればそのとおりに作る必要があります。ですので、おそらく最終的なゴールを達成されるには、ここは URL を工夫すればいいというだけでなく、そのあたりも考慮して作り込む必要があるものと思います。
gh640

2018/12/02 02:40

ちなみに、新しく質問を見た方がすべてのコメントを時系列に追ってくれるとはかぎらないかと思いますので、「 Python3.6 Django2.0です……」のコメントの内容は質問文にも追記されるとよいかと思います。
donadona

2018/12/02 02:57

ありがとうございました。よくよく考えてみたら当然のことですね。ちなみに、質問内容がそれてしまって恐縮ですが、作成したユーザーのみがDLできるようにするのは、どのようなやり方になるのでしょうか?調べてみたいと思いますが、方向性だけ(何を調べればよいか)でも教えていただけないでしょうか?
gh640

2018/12/02 12:17

ローカルで開発をしていると特に、サーバのファイルシステムのパスと URL のパス、ごっちゃになりがちですよね。とてもよくわかります。 / 「作成したユーザーのみがDLできるようにするのは」の件、回答欄で回答させていただきました。
guest

回答2

0

ベストアンサー

URL の問題についてはいったん(問題の原因がはおわかりになったという意味で)解決されたようですので、コメント欄でいただいたこちら ↓ のご質問に回答させていただきますね。

作成したユーザーのみがDLできるようにするのは、どのようなやり方になるのでしょうか?

さまざまな方法があるかと思いますが、定石的な方法の大枠は次のとおりになると思います。

  • a) ダウンロードさせたいファイルはユーザが直接アクセスできないところに置く(つまり Django の media ディレクトリは使わない)
  • b) ファイルダウンロードのための view を作成し、そこでアクセスのチェックを行ってからファイルを返す
  • c) ファイルダウンロードのリンクの href には b) の view の URL を入れる

b) の view の処理の大まかな流れは次のとおりです。

  1. ユーザがログインしているかをチェック → していなかったら 404 (あるいはその他のレスポンス)
  2. ユーザが対象ファイルへのアクセス権限を持っているかをチェック → ダメなら 404
  3. 1 と 2 の両方がパスしたら対象ファイルを開いてレスポンスで返す

3 はファイルサイズがメモリ的に許容できるなら django.http.HttpResponse を、そうでない場合は django.http.StreamingHttpResponse を使う、という形がよいのではないかと思います。

以下 3 についての参考ページです。

尚、 2 を適切に行うためには、 MymodelUser model への参照フィールドを追加して、ファイル生成時に対象ユーザとのひもづけを行っておく、といったことが必要になるかと思います。

あくまでも考え方の一例に過ぎませんが、ご参考になればと思います。がんばってください :)

投稿2018/12/02 12:15

gh640

総合スコア1407

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

donadona

2018/12/04 03:56 編集

詳しいご回答をありがとうございました。 以下のようにして、当初の目的は概ね達成できました。 なお、今のmodelにも、ownerというフィールドを設けて、作成者のuser-idを管理していますので、requestのユーザーIDとダウンロードファイルの所有者を照合するようにしています。 def downloadView(request, pk): if # リクエストのuser.idとdownloadfileの所有者が一致するかチェック download_pth = (ダウンロードファイルへのパス) download_name = '(ファイル名).kmz' if os.path.exists(download_pth ): with open(download_pth , 'rb') as fh: response = HttpResponse(fh.read(), content_type='application/vnd.google-earth.kmz') response['Content-Disposition'] = 'attachment; filename*=UTF-8\'\'{}'format(download_name) コードの意味を完全に理解していないので、無駄な処理もあるかもしれませんし、セキュリティが十分か分かりませんが、とりあえず目的通りの動きができました。 ありがとうございました。
gh640

2018/12/03 23:57

ご状況をお知らせくださりありがとうございます。 > 以下のようにして、当初の目的は概ね達成できました。 そうですか。いい感じに動いてそうですね。 ともあれ目的をご達成されたとのことで何よりです。ご丁寧にお知らせくださりありがとうございました :) (単語のつづり( `application` ? / `Content-Disposition` ? )は念のため再度ご確認されてみてください)
donadona

2018/12/04 03:56

コードのコピペではなく、急いで打ち込んだので多数ミスが有りました。修正しておきました。 ありがとうございました。
guest

0

おそらくパーミッションの問題かと思います。
/ディレクトリから順に該当ファイルまでのパーミッションを適切に設定しましょう。
一旦777にするのがわかりやすいかも。chmodです

投稿2018/12/02 01:39

yamato_user

総合スコア2321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

donadona

2018/12/02 03:00

ご回答ありがとうございました。別の方に回答いただいたように、そもそものところで勘違いしていたようです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問