閉じる

Python×Django入門(環境構築からCRUDまで)

Pythonで本格的なWebアプリケーションを作るなら、Djangoは強力な選択肢です。

認証や管理画面、ORM、テンプレートなどが最初から備わった「電池込み」フレームワークで、初心者でも短時間でCRUDを実装できます。

本記事は環境構築からデータの作成・更新・削除まで、手を動かしながら体系的に学べる内容です。

目次
  1. Django入門(できることと基本用語)
  2. Djangoの環境構築(venvとインストール)
  3. Djangoの基本構成(URL/ビュー/テンプレート/モデル)
  4. DjangoでCRUDを作る(初心者向け手順)
  5. 実行の流れ(おさらい)
  6. 参考: フルソース抜粋
  7. まとめ

Django入門(できることと基本用語)

高機能なWebアプリをPythonで作る理由とDjangoの特徴

なぜDjangoなのか(特徴の全体像)

DjangoはPythonの代表的なWebフレームワークで、開発の初速と保守性を両立します。

特に管理サイト、認証、フォーム、ORM、テンプレート、セキュリティ保護(CSRF対応など)が最初から使え、実務で必要になる機能の大半を標準でカバーしています。

学習を進めると、ジェネリックビューやクラスベースビューなど生産性を上げる機能にも移行しやすいです。

標準装備の機能(抜粋)

機能概要初学者メリット
管理サイト(admin)データをGUIで管理可能まずはGUIでデータを確認できる
ORMPythonのクラスでDB操作SQLを覚える前にCRUDを体験できる
認証ログイン/ログアウト/ユーザー管理ユーザー機能をすぐ試せる
マイグレーションスキーマ変更を安全に反映モデル変更が怖くなくなる
テンプレート表示とロジックを分離分業しやすくHTMLが書きやすい
セキュリティCSRF/XSS/クリックジャッキング対策初学者でも安全な初期設定

初心者が押さえる用語(URL/ビュー/テンプレート/モデル)

MVT(モデル・ビュー・テンプレート)の関係

DjangoはMVCに似たMVTパターンです。

URLにアクセスが来るとビュー(Python関数/クラス)が処理し、必要ならモデル(DB)からデータを取り、テンプレート(HTML)に埋め込んで返します。

用語役割
URLどのビューを呼ぶかのルーティング/posts/で記事一覧ビューへ
ビュー受け取ったリクエストを処理DBから記事を集めてテンプレートへ渡す
テンプレートHTMLにデータを埋め込む記事タイトルをループで表示
モデルDBテーブルの定義Post(title, body, created_at, …)

本記事のゴール(環境構築からCRUDまで)

ゴールと完成イメージ

  • Python仮想環境の準備からDjangoプロジェクト作成までを自力で行う
  • モデル(Post)を作り、記事の一覧・詳細・新規作成・編集・削除(CRUD)を実装
  • 管理サイトにログインしてデータをGUIで確認
    最終的に、初心者が自分のアイデアを形にする最低限の土台を得ます。

Djangoの環境構築(venvとインストール)

Pythonとpipの確認方法

バージョン確認

インストール済みかをコマンドで確認します。

環境によりpythonpyを使います。

Shell
# macOS/Linux
python3 --version
pip3 --version

# Windows
py --version
py -m pip --version
実行結果
Python 3.12.5
pip 24.2 from .../site-packages/pip (python 3.12)

仮想環境の作成と有効化(venv)

venvを使う理由と手順

プロジェクトごとに依存関係を分離するため、仮想環境を使います。

任意の作業フォルダで以下を実行します。

Shell
# macOS/Linux
python3 -m venv .venv
source .venv/bin/activate  # 有効化
# プロンプトに (.venv) が付けばOK

# Windows (PowerShell)
py -m venv .venv
.venv\Scripts\Activate.ps1  # 有効化

有効化後の確認:

Shell
python --version
pip --version

Djangoのインストール(pip)

最新安定版を導入

Shell
pip install "Django>=5.0,<6.0"

インストールログ(例):

text
Collecting Django...
Successfully installed Django-5.0.7 ...

プロジェクト作成(django-admin startproject)

雛形を作成して構造を把握

Shell
django-admin startproject myproject
cd myproject

プロジェクトの構造(抜粋):

text
myproject/
├─ manage.py
└─ myproject/
   ├─ settings.py  # 設定
   ├─ urls.py      # ルーティング
   ├─ asgi.py
   └─ wsgi.py

開発サーバー起動(runserver)

まずは立ち上げて動作確認

Shell
python manage.py runserver
実行結果
Watching for file changes with StatReloader
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

ブラウザでhttp://127.0.0.1:8000/にアクセスし、Djangoのウェルカムページが見えれば成功です。

立ち上げたWebサーバーを終了する場合は、ターミナルでCtrl+Cを押してください。強制終了します。

データベースはSQLiteを使う(初期設定のままでOK)

はじめてはSQLiteが最適

設定不要ですぐ使えるDBとしてSQLiteが既定になっています。

学習の間はそのままで問題ありません。

後でPostgreSQLなどに切り替えるのも容易です。

Djangoの基本構成(URL/ビュー/テンプレート/モデル)

アプリ作成(startapp)とプロジェクトの関係

アプリを作って機能を分割

プロジェクト配下に機能単位のアプリを作ります。

ここではblogというアプリを作成します。

Shell
python manage.py startapp blog

生成物(抜粋):

text
blog/
├─ apps.py
├─ models.py     # DBモデル
├─ views.py      # ビュー
├─ urls.py       # ※自分で作成(後述)
├─ templates/    # HTMLを置く(後述)
└─ static/       # 画像/CSS/JS(後述)

設定(settings.py)の最低限

アプリを有効化し、ロケールも整える

myproject/settings.pyを編集します。

Pythonmyproject/settings.py
# myproject/settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "blog",  # 追加: 作成したアプリ
]

LANGUAGE_CODE = "ja"            # 日本語
TIME_ZONE = "Asia/Tokyo"        # 日本時間
USE_I18N = True
USE_TZ = True                   # タイムゾーン対応は有効のままでOK

# 静的ファイルのURL
STATIC_URL = "static/"

全ての定数は初期化時に定義されているので、どこに書かれているかわからない場合はエディタの検索機能で探してください。

本番ではDEBUG=FalseとALLOWED_HOSTSの設定が必須ですが、学習中のローカル開発では既定のままで構いません。

URL設定(urls.py)の基本

プロジェクトURLからアプリURLへ委譲

まず、アプリ側のurls.pyを新規作成し、ルーティングを定義します。

Pythonblog/urls.py
# blog/urls.py
from django.urls import path
from . import views

app_name = "blog"

urlpatterns = [
    path("", views.index, name="index"),  # トップページ
]

次に、プロジェクトのurls.pyでアプリのURLを読み込みます。

Python
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("blog.urls")),  # blogアプリに委譲
]

ビューの作成(関数ベースビュー)

最初のビューを定義

Python
# blog/views.py
from django.http import HttpResponse

def index(request):
    # 学習の第一歩: シンプルなレスポンスを返す
    return HttpResponse("Djangoへようこそ。これが最初のページです。")

ブラウザでhttp://127.0.0.1:8000/にアクセスし、メッセージが表示されればOKです。

テンプレートの作成(HTMLとテンプレートタグ入門)

テンプレートを使ってHTMLを返す

テンプレートはアプリ配下にtemplates/blogを作って配置します。

Shell
# ディレクトリ作成(必要に応じて)
mkdir -p blog/templates/blog
Python
# blog/views.py
from django.shortcuts import render

def index(request):
    # テンプレートに値を渡す
    context = {"message": "テンプレートから表示しています"}
    return render(request, "blog/index.html", context)
HTML
<!-- blog/templates/blog/index.html -->
<!doctype html>
<html lang="ja">
  <head><meta charset="utf-8"><title>はじめてのテンプレート</title></head>
  <body>
    <h1>{{ message }}</h1>  <!-- {{ }} で変数を表示 -->
  </body>
</html>

静的ファイルの置き方(static)

CSSや画像の配信

アプリ配下にstatic/blogを作り、CSSを置きます。

Shell
mkdir -p blog/static/blog
CSS
/* blog/static/blog/style.css */
body { font-family: system-ui, sans-serif; }
h1 { color: #2a6; }

テンプレートから読み込みます。

HTML
{% load static %}
<link rel="stylesheet" href="{% static 'blog/style.css' %}">

モデル作成(models.py)とマイグレーション

DBテーブルを定義して反映

Python
# blog/models.py
from django.db import models

class Post(models.Model):
    # 記事モデル: タイトルと本文、作成/更新日時
    title = models.CharField(max_length=200, verbose_name="タイトル")
    body = models.TextField(verbose_name="本文")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新日時")

    def __str__(self):
        # 管理画面などでの表示名
        return self.title

マイグレーションを作成・反映します。

Shell
python manage.py makemigrations
python manage.py migrate
実行結果
Migrations for 'blog':
  blog/migrations/0001_initial.py
    - Create model Post
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying blog.0001_initial... OK

管理サイト(admin)の有効化とログイン

管理画面にモデルを登録

Python
# blog/admin.py
from django.contrib import admin
from .models import Post

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ("id", "title", "created_at", "updated_at")
    search_fields = ("title",)

管理ユーザーを作成してログインします。

Shell
python manage.py createsuperuser
# ユーザー名/メール/パスワードを対話入力

サーバーを起動しhttp://127.0.0.1:8000/admin/へアクセス、ログイン後にPostが操作できれば成功です。

上記のようにならない場合、各種コマンドを実行した際のカレントディレクトリや、コマンドの実行漏れ、ファイルを作成する場所を間違えている、コードに転記ミスがあるなどの問題が発生しています。

ここまでの流れで作成されているはずのプロジェクトをダウンロードできるようにしておきますので、何を間違えているのかチェックしてみるといいでしょう。

Django myproject

Djangoのサンプルプロジェクトです。

ログイン情報:
ユーザー名 : user
パスワード : qwerty

DjangoでCRUDを作る(初心者向け手順)

モデル定義とテーブル作成

PostモデルをCRUDの対象にする

すでに定義済みのPostモデルを使います。

初回であればmakemigrationsmigrateを済ませておきます。

以降、画面を通じてPostの作成・編集・削除を実装していきます。

一覧表示(Read一覧)

ビューとテンプレートを用意

Python
# blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post

def post_list(request):
    # 新しい順に並べる
    posts = Post.objects.order_by("-created_at")
    return render(request, "blog/post_list.html", {"posts": posts})
HTML
<!-- blog/templates/blog/post_list.html -->
{% extends "blog/base.html" %}
{% block title %}記事一覧{% endblock %}
{% block content %}
  <h2>記事一覧</h2>
  <p><a href="{% url 'blog:post_create' %}">新規作成</a></p>
  <ul>
    {% for post in posts %}
      <li>
        <a href="{% url 'blog:post_detail' post.pk %}">{{ post.title }}</a>
        <small>作成: {{ post.created_at|date:"Y-m-d H:i" }}</small>
      </li>
    {% empty %}
      <li>まだ記事がありません。</li>
    {% endfor %}
  </ul>
{% endblock %}

ベーステンプレートも作っておくと共通化できます。

HTML
<!-- blog/templates/blog/base.html -->
{% load static %}
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Django Blog{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'blog/style.css' %}">
  </head>
  <body>
    <header>
      <h1><a href="{% url 'blog:post_list' %}">Django Blog</a></h1>
      <nav><a href="{% url 'blog:post_create' %}">新規作成</a></nav>
    </header>
    <main>
      {% block content %}{% endblock %}
    </main>
  </body>
</html>

詳細表示(Read詳細)

1件のレコードを表示する

Python
# blog/views.py
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)  # 見つからない時は404
    return render(request, "blog/post_detail.html", {"post": post})
HTML
<!-- blog/templates/blog/post_detail.html -->
{% extends "blog/base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
  <article>
    <h2>{{ post.title }}</h2>
    <p><small>更新: {{ post.updated_at|date:"Y-m-d H:i" }}</small></p>
    <div style="white-space: pre-wrap;">{{ post.body }}</div>
  </article>
  <p>
    <a href="{% url 'blog:post_update' post.pk %}">編集</a> /
    <a href="{% url 'blog:post_delete' post.pk %}">削除</a> /
    <a href="{% url 'blog:post_list' %}">一覧へ戻る</a>
  </p>
{% endblock %}

新規作成(Create)とフォーム(forms.py)

ModelFormでフォームを自動生成

Python
# blog/forms.py
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    # ModelFormでtitleとbodyのフォームを生成
    class Meta:
        model = Post
        fields = ["title", "body"]
        labels = {"title": "タイトル", "body": "本文"}
Python
# blog/views.py
from .forms import PostForm

def post_create(request):
    if request.method == "POST":
        form = PostForm(request.POST)       # 送信データでフォームを作成
        if form.is_valid():
            form.save()                     # DBへINSERT
            return redirect("blog:post_list")
    else:
        form = PostForm()                   # 空フォーム
    return render(request, "blog/post_form.html", {"form": form, "mode": "create"})
HTML
<!-- blog/templates/blog/post_form.html -->
{% extends "blog/base.html" %}
{% block title %}{% if mode == "create" %}新規作成{% else %}編集{% endif %}{% endblock %}
{% block content %}
  <h2>{% if mode == "create" %}新規作成{% else %}編集{% endif %}</h2>
  <form method="post">
    {% csrf_token %}  <!-- CSRF対策は必須 -->
    {{ form.as_p }}
    <p>
      <button type="submit">{% if mode == "create" %}作成{% else %}更新{% endif %}</button>
      <a href="{% url 'blog:post_list' %}">キャンセル</a>
    </p>
  </form>
{% endblock %}

編集(Update)の実装

既存レコードをフォームに差し込む

Python
# blog/views.py
def post_update(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)  # 既存を上書き
        if form.is_valid():
            form.save()                                # DBへUPDATE
            return redirect("blog:post_detail", pk=post.pk)
    else:
        form = PostForm(instance=post)                 # 初期値入りフォーム
    return render(request, "blog/post_form.html", {"form": form, "mode": "edit"})

削除(Delete)の実装

確認画面を挟んで安全に削除

Python
# blog/views.py
def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        post.delete()                                  # DBからDELETE
        return redirect("blog:post_list")
    return render(request, "blog/post_confirm_delete.html", {"post": post})
HTML
<!-- blog/templates/blog/post_confirm_delete.html -->
{% extends "blog/base.html" %}
{% block title %}削除確認{% endblock %}
{% block content %}
  <h2>削除確認</h2>
  <p>「{{ post.title }}」を削除します。よろしいですか?</p>
  <form method="post">
    {% csrf_token %}
    <button type="submit">削除する</button>
    <a href="{% url 'blog:post_detail' post.pk %}">戻る</a>
  </form>
{% endblock %}

URLとテンプレートの紐付け

画面遷移の要(ルーティング)を整理

ブログアプリのURL定義をまとめます。

Python
# blog/urls.py
from django.urls import path
from . import views

app_name = "blog"

urlpatterns = [
    path("", views.post_list, name="post_list"),
    path("posts/<int:pk>/", views.post_detail, name="post_detail"),
    path("posts/new/", views.post_create, name="post_create"),
    path("posts/<int:pk>/edit/", views.post_update, name="post_update"),
    path("posts/<int:pk>/delete/", views.post_delete, name="post_delete"),
]

プロジェクト側での読み込みは以前の通りです。

Python
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("blog.urls")),
]

テンプレートでは{% url 'blog:post_detail' post.pk %}のように名前付きURLを使うと、パスが変わってもリンクが壊れにくくなります。

動作確認とエラー対処

よくあるつまずきと解決策

  • TemplateDoesNotExist: テンプレートのパスが正しいか確認します。アプリ内ならblog/templates/blog/...の2階層を守るのが安全です。
  • ModuleNotFoundError: INSTALLED_APPS"blog"を追加し忘れていないか確認します。
  • CSRF verification failed: POSTフォームに{% csrf_token %}を入れたか確認します。
  • マイグレーションエラー: モデルを変えたらmakemigrationsmigrateの順に実行します。衝突時はpython manage.py showmigrationsで状況を確認します。
  • 404 Not Found: URLパターンとリンクのnameが一致しているか、pkを正しく渡しているかを再確認します。

開発サーバーのログは手がかりになります。

エラー時はトレースバックを上から順に読み、どのファイルの何行目で止まったかに注目してください。

実行の流れ(おさらい)

1. サーバー起動から画面表示まで

  1. ブラウザが/posts/へアクセス
  2. プロジェクトurls.py→アプリurls.pyの順にマッチ
  3. post_listビューがPostをORMで取得
  4. post_list.htmlにレンダリングしてHTMLを返す
    この一連の流れを理解すると、URL/ビュー/テンプレート/モデルが頭の中でつながるようになります。

参考: フルソース抜粋

blog/views.py(CRUDをまとめて)

Python
# blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post
from .forms import PostForm

def post_list(request):
    posts = Post.objects.order_by("-created_at")
    return render(request, "blog/post_list.html", {"posts": posts})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, "blog/post_detail.html", {"post": post})

def post_create(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("blog:post_list")
    else:
        form = PostForm()
    return render(request, "blog/post_form.html", {"form": form, "mode": "create"})

def post_update(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            form.save()
            return redirect("blog:post_detail", pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, "blog/post_form.html", {"form": form, "mode": "edit"})

def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        post.delete()
        return redirect("blog:post_list")
    return render(request, "blog/post_confirm_delete.html", {"post": post})

blog/urls.py(ルーティング)

Python
# blog/urls.py
from django.urls import path
from . import views

app_name = "blog"

urlpatterns = [
    path("", views.post_list, name="post_list"),
    path("posts/<int:pk>/", views.post_detail, name="post_detail"),
    path("posts/new/", views.post_create, name="post_create"),
    path("posts/<int:pk>/edit/", views.post_update, name="post_update"),
    path("posts/<int:pk>/delete/", views.post_delete, name="post_delete"),
]

blog/models.py(モデル)

Python
# blog/models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200, verbose_name="タイトル")
    body = models.TextField(verbose_name="本文")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新日時")

    def __str__(self):
        return self.title

blog/forms.py(ModelForm)

Python
# blog/forms.py
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ["title", "body"]
        labels = {"title": "タイトル", "body": "本文"}

blog/templates/blog/base.html(ベース)

HTML
{% load static %}
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Django Blog{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'blog/style.css' %}">
  </head>
  <body>
    <header>
      <h1><a href="{% url 'blog:post_list' %}">Django Blog</a></h1>
      <nav><a href="{% url 'blog:post_create' %}">新規作成</a></nav>
    </header>
    <main>{% block content %}{% endblock %}</main>
  </body>
</html>

blog/templates/blog/post_list.html(一覧)

HTML
{% extends "blog/base.html" %}
{% block title %}記事一覧{% endblock %}
{% block content %}
  <h2>記事一覧</h2>
  <p><a href="{% url 'blog:post_create' %}">新規作成</a></p>
  <ul>
    {% for post in posts %}
      <li>
        <a href="{% url 'blog:post_detail' post.pk %}">{{ post.title }}</a>
        <small>作成: {{ post.created_at|date:"Y-m-d H:i" }}</small>
      </li>
    {% empty %}
      <li>まだ記事がありません。</li>
    {% endfor %}
  </ul>
{% endblock %}

blog/templates/blog/post_detail.html(詳細)

HTML
{% extends "blog/base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
  <article>
    <h2>{{ post.title }}</h2>
    <p><small>更新: {{ post.updated_at|date:"Y-m-d H:i" }}</small></p>
    <div style="white-space: pre-wrap;">{{ post.body }}</div>
  </article>
  <p>
    <a href="{% url 'blog:post_update' post.pk %}">編集</a> /
    <a href="{% url 'blog:post_delete' post.pk %}">削除</a> /
    <a href="{% url 'blog:post_list' %}">一覧へ戻る</a>
  </p>
{% endblock %}

blog/templates/blog/post_form.html(作成・編集)

HTML
{% extends "blog/base.html" %}
{% block title %}{% if mode == "create" %}新規作成{% else %}編集{% endif %}{% endblock %}
{% block content %}
  <h2>{% if mode == "create" %}新規作成{% else %}編集{% endif %}</h2>
  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <p>
      <button type="submit">{% if mode == "create" %}作成{% else %}更新{% endif %}</button>
      <a href="{% url 'blog:post_list' %}">キャンセル</a>
    </p>
  </form>
{% endblock %}

blog/templates/blog/post_confirm_delete.html(削除確認)

HTML
{% extends "blog/base.html" %}
{% block title %}削除確認{% endblock %}
{% block content %}
  <h2>削除確認</h2>
  <p>「{{ post.title }}」を削除します。よろしいですか?</p>
  <form method="post">
    {% csrf_token %}
    <button type="submit">削除する</button>
    <a href="{% url 'blog:post_detail' post.pk %}">戻る</a>
  </form>
{% endblock %}

blog/static/blog/style.css(簡易スタイル)

CSS
/* blog/static/blog/style.css */
body { font-family: system-ui, sans-serif; margin: 2rem; }
header h1 a { text-decoration: none; color: #2a6; }
main { margin-top: 1rem; }

まとめ

Djangoは「最初から本気で作れる」実用志向のフレームワークです。

本記事では仮想環境の準備からプロジェクト作成、URL/ビュー/テンプレート/モデルというMVTの要素を丁寧にたどり、管理サイトの活用ModelFormによるCRUDまでを一気通貫で実装しました。

ここまで到達すれば、一覧/詳細/作成/編集/削除というWebアプリの基本骨格を自力で構築できます。

次の一歩としては、ページネーション、認証と権限、クラスベースビュー、汎用ビュー、バリデーションの強化、デプロイなどに挑戦すると、より実務レベルのアプリに進化します。

今日作った最小アプリを起点に、あなたのアイデアをDjangoで形にしていきましょう

Python 実践TIPS - Web・API開発
この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!