Python Django入門 初めの1歩からWEBアプリ作成までの流れ その9 FormView, CreateView, DetailView, ListViewまとめて

models.py

models.py
# Create your models here.
from django.db import models
import datetime
JST = datetime.timezone(datetime.timedelta(hours=9))

# Create your models here.
class SampleListModel(models.Model):
    title = models.CharField('タイトル',max_length=50)
    text = models.TextField('本文')
    url = models.URLField('URL', blank=True)
    created_at = models.DateTimeField('作成日', default=datetime.datetime.now(tz=JST))

    def __str__(self):
        return self.title

class SampleDetailModel(models.Model):
    name = models.CharField('名前',max_length=256)
    feature = models.TextField('特徴')
    list = models.ForeignKey(SampleListModel, on_delete=models.CASCADE, related_name='related_list')

    def __str__(self):
        return self.name

forms.py

forms.py
from .models import SampleListModel, SampleDetailModel
from django.db import models
from django import forms

class SampleListForm(forms.ModelForm):
    class Meta:
        model = SampleListModel
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        for field in self.base_fields.values():
            field.widget.attrs["class"]="form-control"
        super().__init__(*args, **kwargs)

class SampleDetailForm(forms.ModelForm):
    class Meta:
        model = SampleDetailModel
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        for field in self.base_fields.values():
            field.widget.attrs["class"]="form-control"
        super().__init__(*args, **kwargs)  

views.py

views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import CreateView, ListView, DetailView
from .models import SampleListModel, SampleDetailModel
from .forms import SampleListForm, SampleDetailForm
from django.urls import reverse, reverse_lazy

# Create your views here.
class SampleListCreate(CreateView):
    template_name = 'app/list_create.html'
    form_class = SampleListForm
    success_url = reverse_lazy('app:app/list')

class SampleDetailCreate(CreateView):
    template_name = 'app/detail_create.html'
    form_class = SampleDetailForm
    success_url = reverse_lazy('app:app/list')

class SampleList(ListView):
    model = SampleListModel
    context_object_name = "sample_list"
    template_name = 'app/list.html'

class SampleDetail(DetailView):
    model = SampleListModel
    context_object_name = "sample_detail"
    template_name = "app/detail.html"

pj/urls.py

pj/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('app.urls')),
]

app/urls.py

app/urls.py
from django.contrib import admin
from django.urls import path
from . import views

app_name = 'app'

urlpatterns = [
    path('', views.SampleList.as_view(), name='app/list'),
    path('detail/<int:pk>', views.SampleDetail.as_view(), name='app/detail'),
    path('list_create', views.SampleListCreate.as_view(), name='app/list_create'),
    path('detail_create', views.SampleDetailCreate.as_view(), name='app/detail_create'),
]

settings.py

settings.py
"""
Django settings for pj project.

Generated by 'django-admin startproject' using Django 3.2.6.

For more information on this file, see

Django settings | Django documentation
The web framework for perfectionists with deadlines.
For the full list of settings and their values, see
Settings | Django documentation
The web framework for perfectionists with deadlines.
""" from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-!f$ze!g_kk^w09n61tf$9h5+yrpbo7mccflq#jmb@1b1^$99eu' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'pj.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'pj.wsgi.application' # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' import os STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static/"), ) # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

pj/templates/app/base.html

pj/templates/app/base.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Python Django CreateView, ListView, DetailView</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="{% static 'app/style.css' %}">
</head>
<body>
    <header class="page-header wrapper">
        <h1><a href="/"><img class="logo" src="images/logo_zeroterasu.png" alt="ZeroTerasuウェブサイト ホーム"><span> ZeroTerasu WebSite</span></a></h1>
        <nav class="page-nav">
            <ul class="main-nav">
                <li><a href="about.html">プロフィール</a></li>
                <li><a href="works.html">制作実績</a></li>
                <li><a href="https://zeroterasu.com/blog/">ブログ</a></li>
                <li><a href="contact.php">お問い合わせ</a></li>
            </ul>
        </nav>
    </header>
    {% block main %}
    {% endblock %}
    <footer>
        <div class="wrapper">
            <p><small>© 2021 ZeroTerasu</small></p>
            <a href="privacy_policy">プライバシーポリシー</a>
        </div>
    </footer>
</body>
</html>

pj/templates/app/list_create.html

pj/templates/app/list_create.html
{% extends 'app/base.html' %}
{% block main %}
<div class="container my-3">
    <div class="text-center my-3">
        <h2>新しいリストを作成</h2>
    </div>
    <form method="POST"> {% csrf_token %}
        {{ form.as_p }}
        <button class="btn btn-primary form-control" type="submit">登録</button>
    </form>
    <a href="{% url 'app:app/list' %}">リスト一覧ページ</a><br>
    <a href="{% url 'app:app/detail_create' %}">詳細作成ページ</a><br>
</div>
{% endblock %}

pj/templates/app/detail_create.html

pj/templates/app/detail_create.html
{% extends 'app/base.html' %}
{% block main %}
<div class="container my-3">
    <div class="text-center my-3">
        <h2>新しい詳細を作成</h2>
    </div>
    <form method="POST"> {% csrf_token %}
        {{ form.as_p }}
        <button class="btn btn-primary form-control" type="submit">登録</button>
    </form>
    <a href="{% url 'app:app/list' %}">リスト一覧ページ</a><br>
    <a href="{% url 'app:app/list_create' %}">リスト作成ページ</a><br>
</div>
{% endblock %}

pj/templates/app/list.html

pj/templates/app/list.html
{% extends 'app/base.html' %}
{% block main %}
<div class="wrapper">
    <h2>リスト一覧</h2>
    <table class="table">
        <thead>
          <tr>
            <th>リスト名</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {% for sample in sample_list %}
          <tr>
            <td>{{ sample.title }}</td>
            <td><a href="detail/{{ sample.id }}">詳細</a></td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
    <a href="{% url 'app:app/list_create' %}">リスト作成ページ</a><br>
    <a href="{% url 'app:app/detail_create' %}">詳細作成ページ</a><br>
</div>
{% endblock %}

pj/templates/app/detail.html

pj/templates/app/detail.html
{% extends 'app/base.html' %}
{% block main %}
<div class="wrapper">
    <h2>詳細ページ</h2>
    <h2>リスト詳細</h2>
    <table class="table">
      <thead>
        <tr>
          <th scope="col">リスト名</th>
          <th scope="col">本文</th>
          <th scope="col">URL</th>
      </tr>
    </thead>
      <tbody>
        <tr>
          <td>{{ sample_detail.title }}</td>
          <td>{{ sample_detail.text }}</td>
          <td>{{ sample_detail.url }}</td>
        </tr>
      <tbody>
    </table>
    <h3>詳細情報</h3><br>
    <table class="table">
        <thead>
          <tr>
            <th scope="col">name</th>
            <th scope="col">feature</th>
        </tr>
      </thead>
        <tbody>
    {% for detail in sample_detail.related_list.all %}
          <tr>
            <td>{{ detail.name }}</td>
            <td>{{ detail.feature }}</td>
          </tr>
    {% endfor %}
        <tbody>
    </table>
    <br>
    <a href="{% url 'app:app/list' %}">リスト一覧ページ</a><br>
    <a href="{% url 'app:app/list_create' %}">リスト作成ページ</a><br>
    <a href="{% url 'app:app/detail_create' %}">詳細作成ページ</a><br>
</div>
{% endblock %}

admin.py

admin.py
from django.contrib import admin
from .models import *

admin.site.register(SampleListModel)
admin.site.register(SampleDetailModel)

コメント

タイトルとURLをコピーしました