Django開発メモ

目次

Django

0.コマンド一覧

1.環境構築

2.最初のプロジェクト

2.1 Hello, World

2.2 home.html

3.モデル設計

3.1 ブログセクション設計

3.2 実装コード

3.3 モデルAPIのテスト

3.3.1 Pythonコマンドでのオブジェクト作成

3.3.2 モデルマネージャーによるオブジェクト作成

4.ビュー関数

5.検索エンジン設定

6.テンプレート

7.フォーム

7.1 はじめに

7.2 Forms API

7.3 Bootstrapフォームレンダリング

pyファイル詳細

1.settings.py

1.1 静的ファイル

1.2 INSTALLED_APPS

1.3 X_FRAME_OPTIONS

2.urls.py

3.models.py

4.urls.py

よく使う関数

Django

Django開発メモ

0.コマンド一覧

  • Djangoインストール

    pip install django==#version#
    
  • プロジェクト作成

    cd Django
    django-admin startproject #プロジェクト名# 
    
  • アプリケーション作成

    アプリは機能モジュールです

    python manage.py startapp #アプリ名#
    
  • プロジェクト実行

    python manage.py runserver
    
  • プロジェクト停止

    ctrl + c
    
  • 仮想環境終了

    deactivate
    
  • モデルマイグレーション

    boards/migrations ディレクトリに0001_initial.pyというファイルが作成されます。これはアプリケーションモデルの現在の状態を表します。次のステップで、Djangoはこのファイルを使用してテーブルとカラムを作成します。

    python manage.py makemigrations
    

    生成されたファイルをデータベースに適用します

    python manage.py migrate
    
  • Pythonシェル

    python
    

    普通のPythonインタープリタセッションを起動します。任意のPythonコードを実行できますが、Djangoプロジェクトの設定や構成は自動的にロードされません。

    python manage.py shell
    

    特別なDjangoインタラクティブシェルを起動します。現在のDjangoプロジェクトの設定と構成をロードし、シェル内でDjangoプロジェクトと直接やりとりできます。このシェルでは、Djangoのモデルやマネージャーなど、Django固有の機能を手動で設定することなく直接インポートして使用できます。

  • インタラクティブコンソール終了

    exit()
    
  • スーパーユーザー作成

python manage.py createsuperuser

1. 環境構築

2.最初のプロジェクト

2.1 Hello, World

boardsアプリを作成

boards/views.py

from django.http import HttpResponse
def home(request):
   return HttpResponse('Hello, World!')

view homeを定義しました。homeはrequestを受け取り、文字列'Hello, World!'を返します。

djangoはurls.pyでview homeを呼び出します。

boards/urls.py

from django.conf.urls import url
from django.contrib import admin

from boards import views

urlpatterns = [
   re_path(r'^$', views.home, name='home'),
   re_path(r'^admin/', admin.site.urls),
]

re_path(r'^$', views.home, name='home') の役割は:

  • 正規表現を使ってサイトのURLパスを一致させる文字列を定義します。

    正規表現を使用:re_path、正規表現を使用しない:path、古いバージョンのDjangoでは:url

  • Webページがそのパスにアクセスした場合、リクエストは views.home ビュー関数で処理されます。

  • このURLパターンに home という名前を指定し、他の場所から参照できるようにします。

    この名前はプロジェクト内の他の場所で使用できます。例えば、テンプレートで {% url 'home' %} を使ってこのURLを生成したり、ビュー関数で reverse('home') を使ってこのURLを逆引きしたりできます。名前付きURLの利点は、URLパターンが変更されても名前が変わらなければ、他のコードを変更する必要がないことです。

2.2 home.html

home.html


<html>
<head>
   <title>Home</title>
</head>
<body>
   <h1>Boards</h1>
   <ul>
       {% for board in boards %}
           <li>{{ board.name }} - {{ board.description }}</li>
       {% endfor %}
   </ul>
</body>
</html>

boards/view.py

def Home(request):
   boards = Board.objects.all()
   return render(request, 'home.html', {'boards': boards})

renderはDjangoのビュー関数で、レンダリングされたHTMLページを返すための一般的なメソッドです。データ{'boards': boards}をページ'home.html'のテンプレートに渡し、HTTPレスポンスを生成してクライアントに返します。

  1. request: HTTPリクエストオブジェクトで、クライアントが送信したリクエスト情報を含みます。
  2. 'home.html': ページ名で、Djangoはこの名前を使って設定されたテンプレートディレクトリからテンプレートファイルを検索してレンダリングします。
  3. {'boards': boards}: テンプレートに渡すデータを含む辞書です。この例では、boardsBoardオブジェクトのクエリセット(QuerySet)であり、テンプレート内で変数名boardsを通してアクセスされます。

3. モデル設計

3.1 ブログセクション設計

Web Boardクラス図

  • Board:セクション
  • Topic:トピック
  • Post:投稿(注:トピックの返信またはコメント)

トピック(Topic)では、どのセクションに属するかを特定するフィールド(注:外部キーで関連付け)が必要です。

同様に、投稿(Post)にもどのトピックに属するかを示すフィールドが必要で、特定のトピック内で作成された投稿をリストアップできます。

最後に、誰がトピックを開始したか、誰が投稿したかを示すフィールドが必要です。

詳細設計

Board モデルには2つのフィールドがあります。

  • nameフィールドは一意である必要があります。重複名を防ぐためです。
  • descriptionはこのセクションの目的を説明するために使用されます。

Topic モデルには4つのフィールドがあります:

  • subjectはトピックの内容を表します。
  • last_updateはトピックの並び替えに使用されます。
  • starterは誰がトピックを開始したかを識別します。
  • boardはそれがどのセクションに属するかを指定します。

Post モデルには1つあります。

  • messageフィールドは返信の内容を格納します。
  • created_atは並び替え時に使用されます(最初に投稿された投稿が最初になります)。
  • updated_atはユーザーに内容が更新されたことを示します。
  • 同時に、対応するUserモデルへの参照も必要です。
  • 投稿は誰が作成したか、誰が更新したかを示します。

最後にUserモデルです。クラス図ではusername、password、email、is_superuserフラグのみを示しています。これらは現在使用しているほとんどすべてのものです。

注意すべきは、Userモデルを作成する必要はないということです。なぜなら、Djangoはcontribパッケージに既にUserモデルを内蔵しているからです。直接それを使用します。

3.2 実装コード

boards/models.py

from django.db import models
from django.contrib.auth.models import User

class Board(models.Model):
	name = models.CharField(max_length=30, unique=True)
	description = models.CharField(max_length=100)
   
class Topic(models.Model):
	subject = models.CharField(max_length=255)
	last_updated = models.DateTimeField(auto_now_add=True)
	board = models.ForeignKey(Board, related_name='topics')
	starter = models.ForeignKey(User, related_name='topics')
   
class Post(models.Model):
	message = models.TextField(max_length=4000)
	topic = models.ForeignKey(Topic, related_name='posts')
	created_at = models.DateTimeField(auto_now_add=True)
	updated_at = models.DateTimeField(null=True)
	created_by = models.ForeignKey(User, related_name='posts')
	updated_by = models.ForeignKey(User, null=True, related_name='+')

Boardモデル

  • name: 文字数が30文字以内の文字列フィールドで、一意である必要があります。
  • description: 文字数が100文字以内の文字列フィールドです。

Topicモデル

  • subject: 文字数が255文字以内の文字列フィールドです。
  • last_updated: 日時フィールドで、Topicオブジェクトが作成されたときに現在の時間を自動的に設定します。
  • board: Boardモデルに関連する外部キーフィールドで、related_name='topics'を使用します。Boardが削除された場合、関連するTopicも削除されます。
  • starter: Userモデルに関連する外部キーフィールドで、related_name='topics'を使用します。Userが削除された場合、関連するTopicも削除されます。
  • views: 正の整数フィールドで、初期値は0で、Topicの閲覧回数を記録します。

Postモデル

  • message: 文字数が4000文字以内のテキストフィールドです。
  • topic: Topicモデルに関連する外部キーフィールドで、related_name='posts'を使用します。Topicが削除された場合、関連するPostも削除されます。
  • created_at: 日時フィールドで、Postオブジェクトが作成されたときに現在の時間を自動的に設定します。
  • updated_at: 日時フィールドで、空にできます。Postの更新時間を記録します。
  • created_by: Userモデルに関連する外部キーフィールドで、related_name='posts'を使用します。Userが削除された場合、関連するPostも削除されます。
  • updated_by: Userモデルに関連する外部キーフィールドで、空にできます。related_name='+'を使用します。Userが削除された場合、関連するPostも削除されます。

Boardモデルはフォーラムのセクションを表し、名前と説明を含み、関連する投稿数や最新の投稿を取得するメソッドを提供します。

Topicモデルはフォーラムのトピックを表し、トピック名、最終更新日時、所属セクション、開始ユーザー、閲覧回数を含みます。

Postモデルはフォーラムの投稿を表し、メッセージ内容、所属トピック、作成時間、更新時間、作成ユーザー、更新ユーザーを含みます。

対応するMySQLテーブル作成SQL

CREATE TABLE `board` (
   `id` INT AUTO_INCREMENT PRIMARY KEY,
   `name` VARCHAR(30) UNIQUE NOT NULL,
   `description` VARCHAR(100) NOT NULL
);

CREATE TABLE `topic` (
   `id` INT AUTO_INCREMENT PRIMARY KEY,
   `subject` VARCHAR(255) NOT NULL,
   `last_updated` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
   `board_id` INT NOT NULL,
   `starter_id` INT NOT NULL,
   `views` INT UNSIGNED NOT NULL DEFAULT 0,
   FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE CASCADE,
   FOREIGN KEY (`starter_id`) REFERENCES `auth_user`(`id`) ON DELETE CASCADE
);

CREATE TABLE `post` (
   `id` INT AUTO_INCREMENT PRIMARY KEY,
   `message` TEXT NOT NULL,
   `topic_id` INT NOT NULL,
   `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
   `updated_at` DATETIME,
   `created_by_id` INT NOT NULL,
   `updated_by_id` INT,
   FOREIGN KEY (`topic_id`) REFERENCES `topic`(`id`) ON DELETE CASCADE,
   FOREIGN KEY (`created_by_id`) REFERENCES `auth_user`(`id`) ON DELETE CASCADE,
   FOREIGN KEY (`updated_by_id`) REFERENCES `auth_user`(`id`) ON DELETE CASCADE
);

related_nameは逆方向のクエリを行うための属性です。モデルに外部キー(ForeignKey)または多対多関係(ManyToManyField)を定義すると、Djangoは自動的に逆方向の関係を作成し、関連するモデルからこのモデルにアクセスできるようにします。related_nameを使用すると、この逆方向の関係にカスタム名を指定できます。

  • Topicインスタンスを取得
topic = Topic.objects.get(id=1)
  • デフォルトの逆方向関係名を使用(post_set)
posts_default = topic.post_set.all()
  • カスタムの逆方向関係名を使用
posts_custom = topic.posts.all() #該当のTopicに関連するすべてのPostオブジェクトを取得

HTMLテンプレートファイルでは、括弧を使わず、board.topics.allを使用します

データをフィルタリングすることも可能です

board.topics.filter(subject__contains='Hello')

3.3 モデルAPIのテスト

3.3.1 Pythonコマンドでのオブジェクト作成

Pythonシェルを起動

Boardクラスをインポート

from boards.models import Board

新しいboardオブジェクトを作成

board = Board(name='Django', description='This is a board about Django.')

オブジェクトをデータベースに保存

board.save()
3.3.2 モデルマネージャーによるオブジェクト作成

Djangoの標準属性objectsを通じてモデルマネージャーにアクセス

board = Board.objects.create(name='Python', description='General discussion about Python.')

また、objectsを使ってデータベース内のすべての既存セクションをリストアップすることもできます

Board.objects.all()

データベースをクエリして単一のオブジェクトを返すことも可能です

board = Board.objects.get(id=1)
board.name
'Django'

存在しないオブジェクトをクエリすると例外が発生します。

getメソッドのパラメータはモデルの任意のフィールドにすることができます。一意ではない識別子をクエリすると複数のオブジェクトが返され、例外が発生します。

4.ビュー関数

5.検索エンジン設定

manage.pyがあるディレクトリに templates という新しいフォルダを作成します:

myproject/

|-- myproject/

| |-- boards/

| |-- myproject/

| |-- templates/ <-- ここ

| +-- manage.py

+-- venv/

templatesフォルダ内にhome.htmlというHTMLファイルを作成します:

templates/home.html

続きあり

6. テンプレート

7. フォーム

7.1 はじめに

csrf_token テンプレートタグ:

{% csrf_token %}

Djangoは CSRF Token(Cross-Site Request Forgery Token)を使用してすべてのPOSTリクエストを保護します。

データ取得

<input type="text" id="id_subject" name="subject">
<input type="text" id="id_message" name="message">
subject = request.POST['subject']
message = request.POST['message']

具体的な実装

from django.contrib.auth.models import User
from django.shortcuts import render, redirect, get_object_or_404
from .models import Board, Topic, Post
def new_topic(request, pk):
   board = get_object_or_404(Board, pk=pk)
   if request.method == 'POST':
       subject = request.POST['subject']
       message = request.POST['message']
       user = User.objects.first() # TODO: 一時的にログインユーザーとして使用
       topic = Topic.objects.create(
           subject=subject,
           board=board,
           starter=user
       )
       post = Post.objects.create(
           message=message,
           topic=topic,
           created_by=user
       )
       return redirect('board_topics', pk=board.pk) 
     
   return render(request, 'new_topic.html', {'board': board}
)

7.2 Forms API

Forms APIはdjango.formsモジュールで利用できます。

Djangoには2種類のフォームがあります:forms.Form と forms.ModelForm です。

Formクラスは汎用的なフォーム実装です。アプリケーションモデルと直接関連していないデータを処理するために使用できます。

ModelFormはFormのサブクラスで、モデルクラスに関連付けられます。

boards/forms.py

from django import forms
from .models import Topic

class NewTopicForm(forms.ModelForm):
   message = forms.CharField(widget=forms.Textarea(), max_length=4000)
   # Django Forms APIは強力なフォーム検証機能を提供します。フォームフィールドは必須フィールド、最大長、正規表現などの各種検証ルールを定義できます。
   # form.is_valid()メソッドは自動的にフォームデータがこれらのルールに適合するか確認します。
   
   class Meta:
       model = Topic # フォームに関連付けるモデルはTopicです
       fields = ['subject', 'message'] # フォームに含まれるフィールドはsubjectとmessageです

boards/views.py # フォーム未使用

def new_topic(request, pk):
   board = get_object_or_404(Board, pk=pk)
   if request.method == 'POST':
       subject = request.POST['subject']
       message = request.POST['message']
       user = User.objects.first()
       topic = Topic.objects.create(
           subject=subject,
           board=board,
           starter=user
       )
       post = Post.objects.create(
           message=message,
           topic=topic,
           created_by=user
       )
       return redirect('board_topics', pk=board.pk)
   return render(request, 'new_topic.html', {'board': board})

boards/views.py # フォーム使用

def new_topic(request, pk):
   board = get_object_or_404(Board, pk=pk) # Boardオブジェクトを取得します。存在しない場合は404エラーを返します。
   user = User.objects.first()  # TODO: 現在ログイン中のユーザーを取得
   if request.method == 'POST': # POSTリクエストの場合、ユーザーがフォームデータを送信したことを意味します。
       form = NewTopicForm(request.POST) # 新しいNewTopicFormフォームインスタンスを作成し、リクエストのPOSTデータを渡します。
       if form.is_valid(): # form.is_valid()でフォームデータが有効かどうかを確認します。
           topic = form.save(commit=False) # form.saveでTopicオブジェクトを作成しますが、データベースには保存しません。
           topic.board = board
           topic.starter = user
           topic.save()
           post = Post.objects.create(
               message=form.cleaned_data.get('message'),
               topic=topic,
               created_by=user
           )
           return redirect('board_topics', pk=board.pk) # TODO: 作成されたトピックページにリダイレクト
   else:
       form = NewTopicForm() # POSTリクエスト以外の場合は、空のNewTopicFormフォームインスタンスを作成します。
   return render(request, 'new_topic.html', {'board': board,'form': form})

中心部分

if request.method == 'POST':
   form = NewTopicForm(request.POST)
   if form.is_valid():
       topic = form.save()
       return redirect('board_topics', pk=board.pk)
else:
	form = NewTopicForm()
return render(request, 'new_topic.html', {'form': form})	

new_topic.html

<form method="post">
   {% csrf_token %}
   {{ form.as_p }}
	<button type="submit" class="btn btn-success">Post</button>
</form>

formには3つのレンダリングオプションがあります:form.as_table、form.as_ul、form.as_p。

これはフォームのすべてのフィールドを素早くレンダリングする方法です。名前通り、as_tableはtableタグを使用して入力をフォーマットし、as_ulはliタグを使用します。

7.3 Bootstrapフォームレンダリング

保留中

pyファイル詳細

1.settings.py

1.1 静的ファイル

STATICFILES_DIRSは静的ファイルの検索ディレクトリを指定するために使用されます。

プロジェクトのルートディレクトリにstaticフォルダを作成します。

settings.py

STATIC_URL = 'static/'
STATICFILES_DIRS = [
   BASE_DIR / 'static'
]

Python3.4以降のバージョンではBASE_DIR / 'static'を使用することをお勧めします。

以前のバージョンではos.path.join(BASE_DIR, 'static')を使用します。

機能は同等です。

テンプレートの先頭で{ % load static % }タグを使用します。

1.2 INSTALLED_APPS
1.3 X_FRAME_OPTIONS

レスポンスヘッダーのx_frame_optionsを指定するために使用されます。

<frame><iframe>または<object>にページが埋め込まれることを許可するかどうかを指定し、クリックジャッキング攻撃を防ぎます。

一般的な値は:

  • DENY:このページはどのページからも埋め込み不可です。
  • SAMEORIGIN:このページは同じオリジンのページからのみ埋め込み可能です。
  • ALLOW-FROM uri:このページは指定されたURIからのみ埋め込み可能です(あまり使用されません)。

2.urls.py

re_path(regex, view, kwargs=None, name=None)
  • regex:URLパスを一致させるために使用される正規表現です。

  • views:このURLを処理するビュー関数です。

  • kwargs: オプションの辞書で、ビュー関数に追加のキーワード引数を渡すために使用されます。これらの引数はURLキャプチャされた引数とともにビュー関数に渡されます。

  • name=' ':URLパターンの名前で、URLの逆引きに使用されます。

    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive, name='year_archive')
    
    1. テンプレートで

      <a href="{% url 'year_archive' year=2023 %}">2023 Articles</a>
      
    2. ビューで

      from django.urls import reverse
      
      def some_view(request):
         url = reverse('year_archive', args=[2023])
         return redirect(url)
      

      reverse関数を使用してURLを生成し、redirect関数を使用してリダイレクトします。

3. models.py

4. urls.py

よく使う関数

  • render()

    from django.shortcuts import render
    
    def home_view(request):
       context = {
           'title': 'Home Page',
           'message': 'Welcome to our website!',
       }
       return render(request, 'home.html', context)
    
    1. requestは現在のHTTPリクエストオブジェクトです。
    2. 'home.html'はレンダリングするテンプレートファイルの名前です。
    3. contextは2つのキー値ペアを含む辞書:'title''message'です。これらのデータはテンプレートで使用できます。

    home.html

    
    <html>
    <head>
       <title>{{ title }}</title>
    </head>
    <body>
       <h1>{{ message }}</h1>
    </body>
    </html>
    

    このテンプレートでは、{{ title }}{{ message }}はそれぞれ'Home Page''Welcome to our website!'に置き換えられます。

  • redirect()

    redirect関数を使用してリダイレクトします

    from django.shortcuts import redirect
    
    def my_view(request):
       # 別のビューにリダイレクト
       return redirect('another_view')
    
    def another_view(request):
       # 別のビューのロジックを処理
       return render(request, 'another_template.html')
    

    外部URLへのリダイレクト

    from django.shortcuts import redirect
    
    def my_view(request):
       # 外部URLにリダイレクト
       return redirect('https://www.example.com')
    

    パラメータを渡しながらリダイレクト

    from django.shortcuts import redirect
    
    def my_view(request):
       # パラメータを渡して別のビューにリダイレクト
       return redirect('another_view', param1='value1', param2='value2')
    

タグ: Django Python web-development ORM Templates

7月1日 20:16 投稿