Djangoのハイライト:静的アセットとメディアファイルのラングリング(パート4)
公開: 2022-03-10DjangoのWebサイトには、多くのファイルが含まれています。 これは、構成、モデル、ビュー、テンプレートのソースコードだけでなく、静的アセット(CSSとJavaScript、画像、アイコン)でもあります。 それだけでは不十分であるかのように、ユーザーがやって来て、自分のファイルをWebサイトにアップロードしたい場合があります。 開発者を信じられないほどにするのに十分です。 どこでもファイル!
ここで私が言いたいことがあります(警告なしで):「心配しないでください、Djangoはあなたの背中を持っています!」 ただし、残念ながら、静的アセットやメディアファイルを処理する場合は、対処すべき多くの注意事項があります。
今日は、圧縮、キャッシュ、可用性などの要素を考慮しながら、単一サーバー展開とスケーラブル展開の両方のファイルの保存と提供について説明します。 また、CDNと専用ファイルストレージソリューションのコストとメリットについても説明します。
注:これは、Djangoサイトを特定のプラットフォームにデプロイする方法に関するチュートリアルではありません。 代わりに、Djangoハイライトシリーズの他の記事(以下を参照)と同様に、フロントエンドの開発者と設計者がWebアプリケーションを作成するプロセスの他の部分を理解するためのガイドとして意図されています。 今日は、完成したばかりのスタイルホットフィックスまたは美しいグラフィックがマスターにプッシュされた後に何が起こるかに焦点を当てています。 一緒に、安全でパフォーマンスが高く、費用対効果の高い方法でこれらのファイルを世界中のユーザーに提供するためにDjango開発者が利用できる戦略の直感を開発します。
シリーズの前の部分:
- パート1:ユーザーモデルと認証
- パート2:テンプレートによる保存行
- パート3:モデル、管理、およびリレーショナルデータベースの活用
定義
これらの用語のほとんどは非常に単純ですが、この議論のための共有語彙を確立するために少し時間をとる価値があります。
ライブDjangoアプリケーションの3種類のファイルは次のとおりです。
- ソースコード
Djangoフレームワークで作成されたPythonファイルとHTMLファイル。 これらのファイルは、アプリケーションのコアです。 ソースコードファイルは一般的にかなり小さく、キロバイト単位で測定されます。 - 静的ファイル
「静的アセット」とも呼ばれるこれらのファイルには、アプリケーション開発者とサードパーティライブラリの両方によって作成されたCSSとJavaScriptのほか、PDF、ソフトウェアインストーラー、画像、音楽、ビデオ、アイコンが含まれます。 これらのファイルはクライアント側でのみ使用されます。 静的ファイルの範囲は、数キロバイトのCSSからギガバイトのビデオです。 - メディアファイル
プロフィール写真から個人用ドキュメントまで、ユーザーがアップロードしたファイルはすべてメディアファイルと呼ばれます。 これらのファイルは、ユーザーのために安全かつ確実に保存および取得する必要があります。 メディアファイルのサイズは任意です。ユーザーは、数キロバイトのプレーンテキストを数ギガバイトのビデオにアップロードする場合があります。 この規模の後半にいる場合は、この記事で提供する準備よりも専門的なアドバイスが必要になる可能性があります。
Djangoデプロイメントの2つのタイプは次のとおりです。
- シングルサーバー
単一サーバーのDjangoデプロイメントは、まさにそのように聞こえます。すべてが単一サーバー上に存在します。 この戦略は非常に単純で、開発環境によく似ていますが、大量のトラフィックや一貫性のない大量のトラフィックを効果的に処理することはできません。 シングルサーバーアプローチは、学習プロジェクトまたはデモンストレーションプロジェクトにのみ適用可能であり、信頼性の高い稼働時間を必要とする実際のアプリケーションには適用できません。 - スケーラブル
Djangoプロジェクトをデプロイする方法はたくさんあり、ユーザーの要求に合わせて拡張できます。 これらの戦略には、多くの場合、多数のサーバーを起動および停止し、ロードバランサーや管理対象データベースなどのツールを使用することが含まれます。 幸い、この記事では、単一サーバーの展開よりも複雑なものすべてをこのカテゴリに効果的にまとめることができます。
オプション1:デフォルトのDjango
小規模なプロジェクトは、単純なアーキテクチャの恩恵を受けます。 Djangoの静的アセットとメディアファイルのデフォルトの処理は、単純です。 それぞれについて、ファイルを保存し、サーバー上のソースコードのすぐ隣にあるルートフォルダーがあります。 単純。 これらのルートフォルダーは、主にyourproject /settings.py構成を介して生成および管理されます。
静的資産
Djangoで静的ファイルを操作するときに理解する最も重要なことは、 python manage.py collectstatic
コマンドです。 このコマンドは、Djangoプロジェクト内の各アプリの静的フォルダーをライフルで移動し、すべての静的アセットをルートフォルダーにコピーします。 このコマンドの実行は、Djangoプロジェクトをデプロイする上で重要な部分です。 次のディレクトリ構造を検討してください。
- project - project - settings.py - urls.py - ... - app1 - static/ - app1 - style.css - script.js - img.jpg - templates/ - views.py - ... - app2 - static/ - app2 - style.css - image.png - templates/ - views.py - ...
また、 project /settings.pyで次の設定を想定しています。
STATIC_URL = "/static/" STATIC_ROOT = "/path/on/server/to/djangoproject/static"
python manage.py collectstatic
コマンドを実行すると、サーバー上に次のフォルダーが作成されます。
- /path/on/server/to/djangoproject/static - app1 - style.css - script.js - img.jpg - app2 - style.css - image.png
各静的フォルダー内に、アプリの名前を持つ別のフォルダーがあることに注意してください。 これは、静的ファイルが収集された後の名前空間の競合を防ぐためです。 上記のファイル構造でわかるように、これによりapp1 /style.cssとapp2 / style.cssが区別されます。 ここから、アプリケーションは本番環境中にSTATIC_ROOT
でこの構造内の静的ファイルを探します。 そのため、 app1 / templates /のテンプレートで静的ファイルを次のように参照します。
{% load static %} <link rel="stylesheet" type="text/css" href="{% static "app1/style.css" %}">
Djangoは、この動作をモデル化するために、開発中の静的ファイルをどこから取得するかを自動的に判断します。開発中にcollectstatic
を実行する必要はありません。
詳細については、Djangoのドキュメントを参照してください。
メディアファイル
ユーザーのデータベースを備えたプロのネットワーキングサイトを想像してみてください。 これらの各ユーザーには、特にアバター画像と履歴書ドキュメントが含まれている可能性のある関連プロファイルがあります。 その情報の短い例のモデルを次に示します。
from django.db import models from django.contrib.auth.models import User def avatar_path(instance, filename): return "avatar_{}_{}".format(instance.user.id, filename) class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) resume = models.FileField(upload_to="path/string") avatar = models.ImageField(upload_to=avatar_path)
これを機能させるには、静的アセットの場合と同様に、 project /settings.pyに次のオプションが必要です。
MEDIA_URL = "/media/" MEDIA_ROOT = "/path/on/server/to/media"
ImageField
はFileField
を継承するため、同じパラメーターと機能を共有します。 両方のフィールドには、オプションのupload_to
引数があります。この引数は、パスである文字列を受け取り、それをMEDIA_ROOT
に追加してファイルを保存します。このファイルには、 MEDIA_URL
の上の同じパスからアクセスできます。 upload_to
引数は、 avatar_path
関数で示されているように、文字列を返す関数を取ることもできます。
メディアファイルディレクトリとその内容をバージョン管理から除外してください。 2人の開発者が異なるマシンで同じアプリケーションをテストすると、その内容が競合する可能性があります。静的アセットとは異なり、デプロイ可能なDjangoアプリケーションの一部ではありません。
オプション2:Django With Services
私の指針となる哲学は、彼らが得意とするもののためにツールを使用することです。 Djangoはすばらしいフレームワークであり、ユーザー認証、サーバー側のレンダリング、モデルとフォームの操作、管理機能、およびWebアプリケーションの構築に必要なその他の多数の重要な側面をすぐに利用できる優れたツールを提供します。 ただし、静的アセットとメディアファイルを処理するためのツールは、私の意見では、スケーラブルなサイトでの本番環境には適していません。 Djangoのコア開発者は、多くの人が本番環境でこれらのファイルを処理するための代替アプローチを選択していることを認識しています。 フレームワークは、あなたがそうするときにあなたの邪魔にならないようにするのに非常に優れています。 一般的な使用を目的としたほとんどのDjangoサイトは、静的アセットを組み込み、これらの非Django固有のアプローチを使用してメディアファイルを処理することを望んでいます。
CDN上の静的資産
中小規模のプロジェクトは1つがなくても解決できますが、CDN(コンテンツ配信ネットワーク)は使いやすく、あらゆるサイズのアプリケーションのパフォーマンスを向上させます。 CDNは、主に静的アセットであるWebコンテンツを配信および提供する、一般的に世界中のサーバーのネットワークです。 人気のあるCDNには、Cloudflare CDN、Amazon CloudFront、Fastlyなどがあります。 CDNを使用するには、静的ファイルをアップロードしてから、アプリケーションで次のように参照します。
<link rel="stylesheet" type="text/css" href="https://cdn.example.com/path/to/your/files/app1/style.css">
このプロセスは、Djangoデプロイメントスクリプトと簡単に統合できます。 python manage.py collectstatic
コマンドを実行した後、生成されたディレクトリをCDNにコピーし(使用しているサービスによって大幅に異なるプロセス)、Djangoデプロイメントパッケージから静的アセットを削除します。
開発では、本番環境とは異なる静的アセットのコピーにアクセスする必要があります。 このようにして、本番サイトに影響を与えることなく、ローカルで変更を加えることができます。 ローカルアセットを使用するか、CDNの2番目のインスタンスを実行してファイルを配信できます。 CDN_URL
などのカスタム変数を使用してyourproject / settings.pyを構成し、その値をテンプレートで使用して、開発と本番環境で正しいバージョンのアセットを使用していることを確認します。
最後に、CSSおよびJavaScriptの多くのライブラリには、ほとんどのWebサイトで使用できる無料のCDNがあります。 たとえば、Bootstrap 4またはunderscore.jsを読み込んでいる場合は、これらのパブリックCDNを使用することで、開発で独自のコピーを使用する煩わしさや、本番環境で独自のコピーを提供する費用をスキップできます。
専用ファイルストアを備えたメディアファイル
実稼働Djangoサイトは、サイトを実行するサーバー上のどこかにある単純な/ media /フォルダーにユーザーファイルを保存するべきではありません。 しない理由は次の3つです。
- 複数のサーバーを追加してサイトをスケールアップする必要がある場合は、アップロードされたファイルをそれらのサーバー間でコピーおよび同期する何らかの方法が必要です。
- サーバーがクラッシュした場合、ソースコードはバージョン管理システムにバックアップされますが、サーバーを構成していない限り、メディアファイルはデフォルトではバックアップされませんが、そのためには専用のファイルを使用することをお勧めします。ファイルストア。
- 悪意のあるアクティビティが発生した場合は、ユーザーがアップロードしたファイルを、アプリケーションを実行しているサーバーとは別のサーバーに保持することをお勧めします。ただし、これにより、ユーザーがアップロードしたファイルを検証する必要がなくなるわけではありません。
ユーザーがアップロードしたファイルを保存するためにサードパーティを統合するのは本当に簡単です。 モデル内のFileField
のupload_to
値を削除または変更し、いくつかの設定を構成することを除いて、コード内で何も変更する必要はありません。 たとえば、ファイルをAWS S3に保存することを計画している場合は、次のことを行う必要があります。これは、Google Cloud、Azure、Backblaze、または同様の競合サービスでファイルを保存するプロセスと非常によく似ています。
まず、ライブラリboto3
とdjango-storages
storagesをインストールする必要があります。 次に、AWSでバケットとIAMロールを設定する必要があります。これは、この記事の範囲外ですが、ここで手順を確認できます。 これらすべてを構成したら、 project /settings.pyに3つの変数を追加する必要があります。
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" AWS_STORAGE_BUCKET_NAME = "BUCKET_NAME" AWS_S3_REGION_NAME = "us-east-2"
さらに、AWSバケットへのクレデンシャルアクセスを設定する必要があります。 一部のチュートリアルでは、設定ファイルに、または環境変数としてIDと秘密鍵を追加する方法を示しますが、これらは安全ではありません。 代わりに、ここで説明するように、AWSCLIでdjango-storages
を使用してキーを設定します。 django-storages
のドキュメントにも興味があるかもしれません。
開発またはテストメディアファイルが実際のユーザーからのアップロードと混同されないようにする必要があります。 これを回避するのは非常に簡単です。複数のバケットを設定します。1つは開発用(または各開発者用)、1つはテスト用、もう1つは本番用です。 次に、変更する必要があるのは、環境ごとのAWS_STORAGE_BUCKET_NAME
設定だけで、準備は完了です。
パフォーマンスと可用性
あなたのウェブサイトのパフォーマンスと信頼性に影響を与える多くの要因があります。 静的ファイルとメディアファイルを検討する際に、それらを管理するためのアプローチに関係なく重要なものをいくつか示します。
費用
ユーザーにファイルを提供するには、ストレージと帯域幅という2つの理由で費用がかかります。 あなたはあなたのためにファイルを保存するためにホスティングプロバイダーに支払う必要がありますが、ファイルを提供するためにそれらにも支払う必要があります。 帯域幅はストレージよりも大幅に高価です(たとえば、AWS S3は、書き込み時にインターネットに転送されるデータのギガバイトあたり9セントに対して、ストレージのギガバイトあたり2.3セントを請求します)。 S3やCDNのようなファイルストアの経済性は、デジタルオーシャンドロップレットのような一般化されたホストの経済性とは異なります。 高価なファイルをそれらのために設計されたサービスに移動することにより、専門性と規模の経済を活用します。 さらに、多くのファイルストアとCDNは無料プランを提供しているため、それらを使用せずに逃げることができるほど小さいサイトでも、代わりにそれを実行して、追加のインフラストラクチャコストなしでメリットを享受できます。
圧縮とトランスコーディング
写真やビデオなどの静的アセットによって引き起こされる問題のほとんどは、それらが大きなファイルであるためです。 当然、開発者はこれらのファイルを小さくしようとすることでこれに対処します。 非可逆と非可逆の2つの一般的なカテゴリで、圧縮とトランスコーディングを組み合わせてこれを行うには、いくつかの方法があります。 可逆圧縮は、アセットの元の品質を維持しますが、ファイルサイズを比較的適度に小さくします。 非可逆圧縮、または非可逆形式へのトランスコーディングでは、元のアーティファクトの品質の一部が失われる代わりに、ファイルサイズを大幅に小さくすることができます。 この例は、ビデオをより低いビットレートにトランスコードすることです。 詳細については、ビデオ配信の最適化に関するこの記事を確認してください。 Web経由で大きなファイルを提供する場合、帯域幅の速度により、高度に圧縮されたアーティファクトを提供する必要があり、不可逆圧縮が必要になることがよくあります。
YouTubeでない限り、圧縮とトランスコーディングはその場で行われません。 静的アセットは、展開前に適切にフォーマットする必要があります。ユーザーのアップロードに基本的なファイルタイプとファイルサイズの制限を適用して、ユーザーのメディアファイルで十分な圧縮と適切なフォーマットを確保できます。
縮小化
JavaScriptとCSSのファイルは通常、画像ほど大きくはありませんが、多くの場合、圧縮してより少ないバイト数に圧縮することができます。 このプロセスは縮小化と呼ばれます。 ミニファイはファイルのエンコーディングを変更しません。ファイルはテキストのままであり、ミニファイされたファイルは元の言語の有効なコードである必要があります。 縮小されたファイルは元の拡張子を保持します。
縮小されたファイルで削除される主なものは不要な空白であり、コンピューターの観点からは、CSSとJavaScriptのほとんどすべての空白は不要です。 縮小スキームは、変数名を短縮し、コメントを削除します。
最小化はデフォルトでコードを難読化します。 開発者は、縮小されていないファイルのみを使用する必要があります。 展開プロセス中のいくつかの自動ステップでは、ファイルを保存して提供する前にファイルを縮小する必要があります。 サードパーティのCDNが提供するライブラリを使用している場合は、利用可能な場合は、そのライブラリの縮小バージョンを使用していることを確認してください。 HTMLファイルは縮小できますが、Djangoはサーバー側のレンダリングを使用するため、その場で行う処理コストは、ページサイズのわずかな減少を上回る可能性があります。
グローバルな可用性
手紙を隣人に送るのにかかる時間が全国に送るよりも短いのと同じように、世界中よりも近くにデータを送るのにかかる時間が短くなります。 CDNがページのパフォーマンスを向上させる方法の1つは、アセットを世界中のサーバーにコピーすることです。 次に、クライアントがリクエストを行うと、最も近いサーバー(多くの場合エッジノードと呼ばれます)から静的アセットを受信し、ロード時間を短縮します。 DjangoサイトでCDNを使用する利点の1つは、静的アセットのグローバルな配布をコードのグローバルな配布から切り離すことです。
クライアント側のキャッシング
ユーザーの近くのサーバーに静的ファイルを配置するよりも良いことは何ですか? 静的ファイルがユーザーのデバイスにすでに保存されていること! キャッシングは、計算または要求の結果を保存して、それらに繰り返しアクセスできるようにするプロセスです。 CSSスタイルシートを世界中のCDNにキャッシュできるのと同じように、クライアントがサイトからページを初めてロードするときに、クライアントのブラウザにキャッシュできます。 次に、スタイルシートは後続のリクエストでデバイス自体で使用できるため、クライアントはリクエストを減らし、ページの読み込み時間を改善し、帯域幅の使用を減らします。
ブラウザは独自のキャッシュ操作を実行しますが、サイトで大量のトラフィックが発生する場合は、Djangoのキャッシュフレームワークを使用してクライアント側のキャッシュ動作を最適化できます。
結論は
繰り返しになりますが、私の指針となる哲学は、ツールを最高の状態で使用することです。 単一サーバープロジェクトと軽量の静的アセットのみを使用する小規模でスケーラブルなデプロイメントでは、Djangoの組み込みの静的アセット管理を使用できますが、ほとんどのアプリケーションでは、CDNを介して提供されるアセットを分離する必要があります。
プロジェクトが実際の単語での使用を目的としている場合は、Djangoのデフォルトの方法でメディアファイルを保存せず、代わりにサービスを使用してください。 「十分なトラフィック」がインターネットの規模で比較的少数である十分なトラフィックがある場合、アーキテクチャ、開発プロセス、および展開に対する追加の複雑さは、パフォーマンス、信頼性、および使用のコスト削減のためにそれ以上の価値があります。静的ファイルとメディアファイル用に、それぞれCDNとファイルストレージソリューションを分離します。
おすすめの読み物
- パート1:ユーザーモデルと認証
- パート2:テンプレートによる保存行
- パート3:モデル、管理、およびリレーショナルデータベースの活用