知識の枝

"All is well"

Django ランダムなURLをUUIDで作成する方法

約204日前 2021年5月6日19:50
デジタル
Django

改訂履歴


2021/5/6 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回はワンクリックでランダムなURLのページを作成する方法を解説します。


2. ゴール


ボタンを押すと新しいURLが作成され、新しいページに自動で移動する。


3. はじめに


イメージは当ブログの「お気に入り管理アプリ」です。
OneTimeStar

登録したいURLをフォームに入力して「Create Now」ボタンを押すと、新しいページが作成されます。




新しいページのURLはランダムに生成されます。
ランダム生成の例
https://chuna.tech/ots/a7d7a257-8e2f-4682-a49d-4ee3883a2f61/


このランダムな文字列の部分にはUUIDと呼ばれるものを採用しています。

UUID(Universally Unique Identifier)とは、ソフトウェア上でオブジェクトを一意に識別するための識別子である。UUIDは128ビットの数値だが、16進法による550e8400-e29b-41d4-a716-446655440000というような文字列による表現が使われることが多い。元来は分散システム上で統制なしに作成できる識別子として設計されており、したがって将来にわたって重複や偶然の一致が起こらないという前提で用いることができる。

UUID - Wikipedia


重要なのは「重複や偶然の一致が起こらない」という点です。
この方法を採用することで「URLを知っている人以外はアクセスできない」疑似的な個人用URLが作成できます。

ユーザー登録してもらう必要が無い為、お手軽に使用可能です。


4. DjangoとUUID


4.1 - UUIDフィールド


DjangoでUUIDを使う場合、models.pyのUUIDFieldを使用すると簡単に実装できます。
以下はモデルの一例です。UUIDを使う際はインポートが必要です。

models.py
from django.db import models
import uuid

class RandomURL(models.Model):

random_url = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

def __str__(self):
return str(self.random_url)
上記は最も簡単な構成です。

この「RandomURL」モデルが生成されたとき、自動でUUIDが作られ「random_url」フィールドに値が保存されます。

この「random_url」に入っている値を利用して新しいページを作成します。


4.2 - ページの作成


ページを作成する簡単な流れとしては、

①「ページ作成」ボタンが押される。
②POSTのリクエストを受け取り、views.py内で「RandomURL」モデルが作成される。
③「RandomURL」モデルの「random_url」フィールドのUUIDの値を変数として取り出す。
④新規ページへのリダイレクトの際にUUIDの変数を渡す。
⑤urls.pyの新規ページが呼び出され、URLの一部にUUIDの変数を代入する。
⑥新規ページのviewを経由してランダムなURLの新規ページが表示される。


図解すると下記のようなイメージです。



上記の流れを順番に実装します。

※POSTを利用せず、単純に新規ページ作成ビューを用意してそこで処理させる方法が一般的です。
POSTを利用すると何かと便利なことがあるので、今回はその方法を解説します。


4.3 - POSTの処理


POSTする対象は何でも良いです。
「RandomURL」モデルとは異なる別のモデルを用意し、そのモデルを作成するフォーム&POSTでもOKです。

とにかく「POST」を処理する流れで「RandomURL」モデルを作ります。

views.pyのビューの中にPOSTリクエストを受け取った場合の処理を作ります。
下記例では「Star」というお気に入りを管理するモデルを作成する「CreateStarForm」フォームがPOSTされた場合の処理が書かれています。

views.py
template = 'star_index.html'

if request.method == "POST":
form = CreateStarForm(request.POST)

if form.is_valid():
new_page = RandomURL.objects.create() #ここ重要①
uuid = get_object_or_404(RandomURL, random_url=new_page.random_url) #ここ重要②

new_star = form.save(commit=False)
new_star.random_url = uuid
new_star.save()

return redirect('ots:star', star_id=new_star.random_url) #ここ重要③
大切な部分だけ抜き出して記載しています。


「Star」というモデルには、紐づく「RandomURL」モデルを設定するフィールド「random_url」があります。

models.py
class Star(models.Model):
"""Star model"""
url = models.CharField(verbose_name='url', max_length=255) #お気に入りページのURLを管理するフィールド
random_url = models.ForeignKey(RandomURL, verbose_name='page_url', on_delete=models.CASCADE) #紐づくページ(RandomURL)を定義するフィールド

def __str__(self):
return self.title



重要ポイント①
RandomURLモデルを生成する。
new_page = RandomURL.objects.create()
「objects.create()」メソッドを使い、RandomURLモデルを生成し、変数「new_page」に格納しています。


重要ポイント②
uuid = get_object_or_404(RandomURL, random_url=new_page.random_url)
さっき①で作ったモデルを呼び出す処理です。
※今更ですがこの処理は無くても良かったかもしれません。わざわざ呼び出さなくても既に「new_page」という変数に入っている為。
(一応解説を続けます)

「get_object_or_404」メソッドで「RandomURL」モデルの「random_url」フィールドが、先ほど作ったモデル「new_page」の「random_url」フィールドと一致するモデルを呼び出しています。
呼び出した後、変数「uuid」に格納しています。

※つまり「new_page」と「uuid」の中身は同じだということ。下記のようにしても動作したので「不要」で確定です。
下記のように書き換えても問題ありません。
if form.is_valid():
new_page = RandomURL.objects.create()

new_star = form.save(commit=False)
new_star.random_url = new_page
new_star.save()




呼び出したモデルは「Star」モデルの「random_url」フィールドで「紐づくページ(RandomURL)」として割り当てています。
new_star.random_url = uuid
ここはあまり重要ではないです。


重要ポイント③
return redirect('ots:star', star_id=new_star.random_url)
リダイレクト先を指定しつつ、urls.pyに渡す変数を定義しています。

リダイレクト先は「'ots:star'」です。「app名: パス名」という書き方です。
これはurls.pyで定義しているパス名です。
urls.py
from django.urls import path
from . import views

app_name = 'ots'

urlpatterns = [
path('', views.IndexView, name='index'),
path('<uuid:star_id>/', views.OneTimeStar, name='star'), #ここがリダイレクト先
]

urls.pyに渡した変数「star_id」には「new_star.random_url」が入っています。

「new_star.random_url」の中には先ほどの処理の流れで「新規ページのUUID」が入れられています。
つまり star_id = a7d7a257-8e2f-4682-a49d-4ee3883a2f61 という感じになります。


urls.pyのパスを見てみましょう。
path('<uuid:star_id>/',
」の部分に上記のUUIDが入ります。
したがってURLとしては
https://chuna.tech/ots/a7d7a257-8e2f-4682-a49d-4ee3883a2f61/
のようになります。


このパスをブラウザで表示する際の処理はviews.pyの「OneTimeStar」ビューに記載されています。
views.OneTimeStar


views.pyに処理の内容が書かれています。
views.py
def OneTimeStar(request, star_id):
template = 'star_page.html'
...
...
...
「star_page.html」を表示する指示になっています。


おおまかな処理の流れについては以上です。


5. さいごに


POST処理の中に該当POSTの内容を保存する処理を書くだけではなく、今回の解説のように別のモデルを生成してそのパラメーターを活用する手段があります。
複雑な処理も実行できるようになりますので、ぜひ使ってみて下さい。