Pythonでwebサイトの構築　Part4 ブログサイト完成

[前回の記事](https://qiita.com/Taku_nakahara/items/a221ca689edcf4fce113)はDBの構築とadminsサイトへのデータ登録を行いました。
今回のきじではいよいよブログサイト編ラストになります。
記事一覧表示から詳細の表示までになります。
今回はまず完成したページから見てみましょう。
<h2>完成したページ</h2>
<h3>記事一覧</h3>
url:/localhost:8000/index

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/792062c8-86f1-773a-bc31-8db37bffe960.png)

<h3>記事詳細</h3>
「記事本文」をクリックすると表示されます。url:/localhost:8000/article/該当するpk

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/257157a5-03a5-0420-3daf-675485988a88.png)
文章についてはネットから適当に拾った文章なのでご了承ください。
それではソースコードを見てみましょう。

<h2>投稿一覧ページ</h2>
投稿一覧ページのコードは以下のようになります。
ここではPart2(https://qiita.com/Taku_nakahara/items/7dbde3dcd9388aab7d57)で飛ばしていたheader.htmlのaタブ内の構文についても簡単に説明します。

djangoでは<a href = "{% url 'app_name:name' %}"></a>とすることでurls.pyから該当のviewを呼び出せるためリンクとして使われます。
記事詳細などはDB登録時点でそれぞれプライマリーキーが付与されており、articleテーブルのpk番目とすることで該当記事が呼び出せたりもします。

```HTML:index.html
{% extends "base.html"%} 
{% load static %}

{% block content%}
<div class = 'container'>
    {% if category %}
        <h3>{{ category }}カテゴリーの記事</h3>
    {% else %}
        <h1>記事一覧</h1>
    {% endif %}
    <div class = 'box-container'>
        {% for article in article_list %}
        <div class = 'box'>
            <div class = 'article'>
                <h5 class = 'article-title'><a href = '{% url 'polls:detail' article.pk %}'>{{ article.title }}</a></h5>
                <br></br>
                <p><a class = 'button' href = '{% url 'polls:detail' article.pk %}'>記事本文を見る</a></p>
                <br>
                <p>{{ article.date }}</p>
                <p><a href = '{% url 'polls:category' article.category %}'>カテゴリー : {{ article.category }}</a></p>
            </div>
        </div>
        {% endfor %}
    </div>

</div>
{% endblock %}
```


```Python:urls.py
from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.TopView.as_view(), name = 'top'),
    path('index/', views.IndexView.as_view(), name = 'index'),
    path('category/<str:category>', views.CategoryView.as_view(), name = 'category'),
]
```

```Python:views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.views.generic import ListView
from .models import Article, Category

class IndexView(ListView):
    model = Article
    context_object_name = 'article_list'
    template_name = 'index.html'

    def get_queryset(self):
        return Article.objects.order_by('-date')

class CategoryView(ListView):
    template_name = 'index.html'

    def get_queryset(self):
        #category = get_object_or_404(Category, pk = self.kwargs['pk'])
        category = Category.objects.get(name = self.kwargs['category'])
        queryset = Article.objects.order_by('-date').filter(category = category)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        #context['category'] = get_object_or_404(Category, pk = self.kwargs['pk'])
        context['category'] = self.kwargs['category']
        return context
```

<h5>{{article.title}}について</h5>
views.py内のcontext_object_nameで'article_list'を指示しました。これによりArticleテーブル内のデータをすべてarticle_listという名前のリストに格納しています。記事一覧ではそれらを表示するためindex.html内のfor文で一つずつ取り出しています。そしてarticle.titleとすることでtitleを取り出しています。

<h5>categoryを表示するには</h5>
下記のようにcontext.pyを作成し、category_listに格納することでテンプレート上でforぶんを利用し、取得可能です。今回はヘッダーのカテゴリーのドロップダウン実装時に利用しました。


```Python:context.py
from .models import Category

def common(request):
    context = {
        'category_list':Category.objects.all(),
    }
    return context
```




<h2>記事詳細</h2>
記事詳細のソースコードは以下になります。

```HTML:index.html
{% extends 'base.html' %}
{% load static %}
{% block title %}ブログ{% endblock %}
{% block content%}
<div class = 'container'>
    <h2>{{ article.title }}</h2>
    <p>{{ article.date }} / <a href = '{% url 'polls:category' article.category %}'>{{ article.category }}</a></p>
    <p>{{ article.text | safe }}</p>

    <br></br>
    <div class = 'relate-content'>
        <h3>関連記事</h3>
        <br></br>
        {% if article.relate_article.all %}
            <h4>関連記事はこちら</h4>
            {% for re_article in article.relate_article.all %}
            <div class = 'box'>
                <div class = 'article'>
                    <h5><a href = '{% url 'polls:detail' re_article.pk %}'>{{ re_article }}</a></h5>
                    <br></br>
                <p><a class = 'button' href = '{% url 'polls:detail' re_article.pk %}'>記事本文を見る</a></p>
                <br>
                <p>{{ article.date }}</p>
                <p><a href = '{% url 'polls:category' article.category %}'>カテゴリー : {{ article.category }}</a></p>
                </div>
            </div>
            {% endfor %}
        {% else %}
            <h4>関連記事はありません。</h4>
        {% endif %}
</div>

{% endblock %}
```


```Python:urls.py
from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.TopView.as_view(), name = 'top'),
    path('index/', views.IndexView.as_view(), name = 'index'),
#追加
    path('article/<int:pk>/', views.ArticleDetail.as_view(), name = 'detail'),
    path('category/<str:category>', views.CategoryView.as_view(), name = 'category'),
]
]
```

```Python:views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.views.generic import ListView, TemplateView, DetailView
from .models import Article, Category
# Create your views here.
class TopView(TemplateView):
    template_name = 'top.html'

class IndexView(ListView):
    model = Article
    context_object_name = 'article_list'
    template_name = 'index.html'

    def get_queryset(self):
        return Article.objects.order_by('-date')
#追加
class ArticleDetail(DetailView):
    model = Article
    template_name = 'detail.html'

class CategoryView(ListView):
    template_name = 'index.html'

    def get_queryset(self):
        #category = get_object_or_404(Category, pk = self.kwargs['pk'])
        category = Category.objects.get(name = self.kwargs['category'])
        queryset = Article.objects.order_by('-date').filter(category = category)
        return queryset
```

<h5>関連記事について</h5>
detail.html内のarticle.relate_article.allでArticleテーブル内に存在するrelate_articleをすべて取り出し、それがあれば表示するというif文を作成しています。

<h5>おまけ</h5>
このサイトのようなデザインを作成するCSSは以下です。

```CSS:style.css
header {
    padding-bottom: 100px;
}

header .navbar-brand {
    margin-left: 50px;
}

.container {
    width: 1000px;
    margin-left: auto;
    margin-right: auto;
}

.container h1 {
    text-align: center;
    margin-bottom:30px;
}

.container h3 {
    text-align: center;
    margin-bottom:30px;
}

.relate-content {
    margin-bottom: 100px;
}

.relate-content h4 {
    text-align: center;
}

.container h5 {
    text-align: left;
}

.box {
    text-align: center;
    float: left;
    width: 300px;
    height: 300px;
    margin: 20px 10px 10px 10px;
    background-color: #fff;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.16);
    color: #212121;
}

a {
    text-decoration: none;
}

.article {
    display: inline-block;
}

.article {
    text-align: center;
}

.article-title {
    margin-top: 50px;
    margin-bottom: 10px;
}

.button {
    width: 100%;
    display       : inline-block;
    border-radius : 5%;          
    font-size     : 18pt;       
    text-align    : center; 
    cursor        : pointer;    
    padding       : 12px 12px; 
    background    : #000066;   
    color         : white;
    line-height   : 1em;
    transition    : .3s; 
    border        : 2px solid #000066;
  }

  .button:hover {
    box-shadow    : none; 
    color         : #000066; 
    background    : #ffffff;
  }
```

<h2>サイト完成！</h2>
完成したサイトは以下のようになります。
<h5>トップページ</h5>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/670804a8-66ed-377f-451c-f953a4b12ed3.png)
<h5>投稿一覧</h5>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/fea876cd-8d9d-5974-58b5-a4441a8131cf.png)
<h5>投稿詳細</h5>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/374d2348-feca-028c-6abd-aeb7e3a4f7cb.png)
<h5>上の関連記事をクリック</h5>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/4909955d-238b-9897-7ec0-2c946e7b51b3.png)

<h5>カテゴリーごとでの記事(例Python)</h5>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402159/41a6751e-4b64-20a4-df38-17a300563872.png)

これで以上になります。質問等ありましたら気軽にコメントください！！
ソースコード全文は[GitHub](https://github.com/TakuyaNakahara-prg/myblog)に記載しています。