Django チュートリアル: 地域図書館ウェブサイト　（その１）

次のサイトの Part5 (Creating our home page) までを行ってみました。
[Django チュートリアル: 地域図書館ウェブサイト](https://developer.mozilla.org/ja/docs/Learn/Server-side/Django/Tutorial_local_library_website)

Part5 まで行うと次のような表示を出すことが出来ます。
![library_mar13.png](https://qiita-image-store.s3.amazonaws.com/0/179446/ebd0ae7f-90ed-f191-d879-37ddf41c9c51.png)

1) プロジェクトの作成

```bash
django-admin startproject locallibrary
cd locallibrary
```

2) アプリの作成

```bash
python manage.py startapp catalog
```

3) アプリの登録

```py:locallibrary/settings.py
（省略）
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'catalog.apps.CatalogConfig',       # 挿入
]
（省略）
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(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',
            ],
        },
    },
]
（省略）
```

4) URL の設定

```py:locallibrary/urls.py
from django.contrib import admin
from django.urls import path

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

# Use include() to add paths from the catalog application 
from django.urls import include
from django.urls import path

urlpatterns += [
    path('catalog/', include('catalog.urls')),
]

#Add URL maps to redirect the base URL to our application
from django.views.generic import RedirectView
urlpatterns += [
    path('', RedirectView.as_view(url='/catalog/', permanent=True)),
]

# Use static() to add url mapping to serve static files during development (only)
from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
```
>catalog/urls.py は作成します。

```py:catalog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]
```

5) catalog/views.py の作成

```py:catalog/views.py
from django.shortcuts import render

# Create your views here.

from catalog.models import Book, Author, BookInstance, Genre

def index(request):
    """View function for home page of site."""

    # Generate counts of some of the main objects
    num_books = Book.objects.all().count()
    num_instances = BookInstance.objects.all().count()
    
    # Available books (status = 'a')
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()
    
    # The 'all()' is implied by default.    
    num_authors = Author.objects.count()
    
    context = {
        'num_books': num_books,
        'num_instances': num_instances,
        'num_instances_available': num_instances_available,
        'num_authors': num_authors,
    }

    # Render the HTML template index.html with the data in the context variable
    return render(request, 'catalog/index.html', context=context)
```

6) catalog/models.py の作成

```py:catalog/models.py
from django.db import models

# Create your models here.


class Genre(models.Model):
    """Model representing a book genre."""
    name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
    
    def __str__(self):
        """String for representing the Model object."""
        return self.name

from django.urls import reverse # Used to generate URLs by reversing the URL patterns

class Book(models.Model):
    """Model representing a book (but not a specific copy of a book)."""
    title = models.CharField(max_length=200)

    # Foreign Key used because book can only have one author, but authors can have multiple books
    # Author as a string rather than object because it hasn't been declared yet in the file
    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
    
    summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book')
    isbn = models.CharField('ISBN', max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>')
    
    # ManyToManyField used because genre can contain many books. Books can cover many genres.
    # Genre class has already been defined so we can specify the object above.
    genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
    
    def __str__(self):
        """String for representing the Model object."""
        return self.title
    
    def get_absolute_url(self):
        """Returns the url to access a detail record for this book."""
        return reverse('book-detail', args=[str(self.id)])

import uuid # Required for unique book instances

class BookInstance(models.Model):
    """Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular book across whole library')
    book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True) 
    imprint = models.CharField(max_length=200)
    due_back = models.DateField(null=True, blank=True)

    LOAN_STATUS = (
        ('m', 'Maintenance'),
        ('o', 'On loan'),
        ('a', 'Available'),
        ('r', 'Reserved'),
    )

    status = models.CharField(
        max_length=1,
        choices=LOAN_STATUS,
        blank=True,
        default='m',
        help_text='Book availability',
    )

    class Meta:
        ordering = ['due_back']

    def __str__(self):
        """String for representing the Model object."""
        return f'{self.id} ({self.book.title})'


class Author(models.Model):
    """Model representing an author."""
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField('Died', null=True, blank=True)

    class Meta:
        ordering = ['last_name', 'first_name']
    
    def get_absolute_url(self):
        """Returns the url to access a particular author instance."""
        return reverse('author-detail', args=[str(self.id)])

    def __str__(self):
        """String for representing the Model object."""
        return f'{self.last_name}, {self.first_name}'
```

7) マイグレーション

```bash
python manage.py makemigrations
python manage.py migrate
```

8) テンプレートの作成

```bash
mkdir catalog/templates
mkdir catalog/templates/catalog
mkdir catalog/static
mkdir catalog/static/css
```

```html:catalog/templates/catalog/base_generic.html
<!DOCTYPE html>
<html lang="ja">
<head>
  {% block title %}<title>Local Library</title>{% endblock %}
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
  <!-- Add additional CSS in static file -->
  {% load static %}
  <link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>
<body>
  <div class="container-fluid">
    <div class="row">
      <div class="col-sm-2">
      {% block sidebar %}
        <ul class="sidebar-nav">
          <li><a href="{% url 'index' %}">Home</a></li>
          <li><a href="">All books</a></li>
          <li><a href="">All authors</a></li>
        </ul>
     {% endblock %}
      </div>
      <div class="col-sm-10 ">{% block content %}{% endblock %}
	2019年3月12日<p />
	</div>
    </div>
  </div>
</body>
</html>
```

```html:catalog/templates/catalog/index.html
{% extends "catalog/base_generic.html" %}

{% block content %}
  <h1>図書館のホームページ</h1>
  <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p>
  <h2>Dynamic content</h2>
  <p>The library has the following record counts:</p>
  <ul>
    <li><strong>Books:</strong> {{ num_books }}</li>
    <li><strong>Copies:</strong> {{ num_instances }}</li>
    <li><strong>Copies available:</strong> {{ num_instances_available }}</li>
    <li><strong>Authors:</strong> {{ num_authors }}</li>
  </ul>
{% endblock %}
```

```css:catalog/static/css/styles.css
.sidebar-nav {
    margin-top: 20px;
    padding: 0;
    list-style: none;
}
```

9) 開発サーバーの起動

```bash
python manage.py runserver
```

ブラウザーで http://127.0.0.1:8000/ にアクセス
まだデータが入っていないので、0 が表示されます。
![library_aa.png](https://qiita-image-store.s3.amazonaws.com/0/179446/ec043ac1-d6ea-7ed4-4180-5d56093e56e0.png)

10) スーパーユーザーの作成
データを入れる為にスーパーユーザーを作成します。

```bash
python manage.py createsuperuser
```

実行時の様子

```text
$ python manage.py createsuperuser
Username (leave blank to use 'uchida'): admin
Email address: test@test.com
Password: 
Password (again): 
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
```

11) catalog/admin.py の編集
データベースを編集できるように設定します。

```py:catalog/admin.py
from django.contrib import admin

# Register your models here.

from catalog.models import Author, Genre, Book, BookInstance

admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Genre)
admin.site.register(BookInstance)
```

12) 開発サーバーを起動して、http://127.0.0.1:8000/admin　にアクセス
![library_bb.png](https://qiita-image-store.s3.amazonaws.com/0/179446/7614bc74-5fc3-4786-5c03-fe31477d552f.png)

ログインすると
![library_cc.png](https://qiita-image-store.s3.amazonaws.com/0/179446/bcf259f6-bf76-e326-18f2-86ef6054d7aa.png)

13) データの入れ込み
![library_dd.png](https://qiita-image-store.s3.amazonaws.com/0/179446/2efc7f57-9759-78e9-41e1-f6dc1a755297.png)

![library_ee.png](https://qiita-image-store.s3.amazonaws.com/0/179446/544a5331-bdbe-450c-11c4-d97bba2aff70.png)

14) admin からログアウトしてカタログを確認
本を３冊、作者を一人登録して、
http://127.0.0.1:8000
にアクセスすると、
次のように表示されます。

```text
Books: 3
Copies: 0
Copies available: 0
Authors: 1
```

続きは次の通り
[Django チュートリアル: 地域図書館ウェブサイト　（その２）](https://qiita.com/ekzemplaro/items/bdb06eb48524455ea5f9)
[Django チュートリアル: 地域図書館ウェブサイト　（その３）](https://qiita.com/ekzemplaro/items/8580f00c107b70726ceb)
[Django チュートリアル: 地域図書館ウェブサイト　（その４）](https://qiita.com/ekzemplaro/items/092b012fb4a773fd4948)
[Django チュートリアル: 地域図書館ウェブサイト　（その５）](https://qiita.com/ekzemplaro/items/31296adfaad63de8da8a)
[Django チュートリアル: 地域図書館ウェブサイト　（その６）](https://qiita.com/ekzemplaro/items/54c13844e68b4eb4d22f)
[Django チュートリアル: 地域図書館ウェブサイト　（その７）](https://qiita.com/ekzemplaro/items/a32b648d32fef3c4f6a5)