Djangoで掲示板アプリを1から作るの。（その3）

>その2
https://qiita.com/TuruMaru/items/8b55d1e134f29b8a8dcd

#ちょっとだけCSS
```
$mkdir static
$touch base.css
```

プロジェクト直下に`static`ディレクトリを作り、その中にcssファイルを作成します。
staticは静的という意味で、静的なファイルを入れておくみたいです。

```python:mysite/setting.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
```

設定ファイルにこれを追加する。

```html:templates/base.html
{% load staticfiles %}   ←これを追加
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    ↓これを追加
    <link rel="stylesheet" href="{% static 'base.css' %}">
    <title>{% block page_title %}{% endblock %}</title>

</head>

```

これでcssが使えます。
ちょっとめんどくさいですね。

投稿を表示する機能を作る前にbaseのHTMLとCSSをヒョヒョイっと書いちゃいます。

```html:templates/base.html
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="{% static 'base.css' %}">
    <title>{% block page_title %}{% endblock %}</title>

</head>
<body>
<nav>
    <p class="site-name">Blog</p>
    <ul>
        <li><a href="{% url 'posts:index' %}">Top</a></li>
        <li><a href="{% url 'posts:write' %}">Write</a></li>
    </ul>
</nav>

<div class="title">
    <h1>{% block title %}{% endblock %}</h1>
</div>

<hr>

<div class="content">
    {% block content%}{% endblock %}
</div>

<hr>

</body>
</html>
```

```css:static/base.css
html, body{
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

body, h1, hr {
    margin: 0px;
}

a{
    color: #e8e8e8;
}

nav p{
    margin: 0px;
    font-size: 30px;
}

nav{
    padding: 10px 10px;
    color: #e8e8e8;
    background-color: #41a888;
}

nav .site-name{
    display: inline-block;
}

nav ul{
    margin: 0px;
    padding: 0px;
    float: right;
}

nav ul li{
    padding: 10px;
    display: inline-block;
}

.title{
    margin: 21px 50px;
}

.content{
    margin: 20px 50px;
}

```

`view.py`と`urls.py`に投稿を書く画面(write)を追加します。

```python:posts/views.py
class WriteView(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'posts/write.html')


write = WriteView.as_view()
```

```python:posts/urls.py
app_name = 'posts'
urlpatterns = [
    path('', views.index, name='index'),
    path('write/', views.write, name='write'), ←これを追加
]
```
<img width="909" alt="スクリーンショット 2019-11-05 11.24.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519379/805805f2-5b1c-e6ef-8e60-ea2c46787dc7.png">

そしたらこんな感じに整います。

投稿一覧画面(post)と投稿を書く画面(write)のどっちを先にやろうかな〜って考えたんですけど、投稿を書く画面(write)からやっちゃいます。

# 投稿作成画面

入力フォームを作成し、入力内容をデータベースに保存します。

### 流れ
1. form.pyの作成
2. views.pyの作成
3. htmlの作成

---
## まずはフォームだけ

```
$cd posts
$touch form.py
```

```python:posts/form.py
from django import forms
from .models import Posts


class WriteForm(forms.ModelForm):
    class Meta:
        #モデルを指定
        model = Posts
        #フォームとして表示したいカラムを指定
        fields = ('text',)
```

```python:posts/views.py
from django.shortcuts import render

# Create your views here.
from django.views.generic import View
#form.pyからフォームをインポート
from .form import WriteForm


class IndexView(View):
    def get(self,request, *args, **kwargs):
        return render(request, 'posts/post.html')


index = IndexView.as_view()


class WriteView(View):
    def get(self, request, *args, **kwargs):
        #値付きでhtmlファイルに飛ぶ
        return render(request, 'posts/write.html', {'form': WriteForm})


write = WriteView.as_view()
```

```python:templates/posts/write.html
{% extends "base.html" %}

{% block page_title %}Write{% endblock %}
{% block title %}Write{% endblock %}

{% block content %}
    <form method="post" action="{% url 'posts:write' %}">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="button">投稿</button>
    </form>
{% endblock %}
```

できる画面がこれです。
<img width="911" alt="スクリーンショット 2019-11-05 16.24.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519379/8d2261d6-b4d1-3cc0-601f-c0d8b90dc94a.png">



書くことはそんなに多くないですよね。HTMLなんて本当はもっと書くことあります。
ここでコードを少なくしているのは、`form.py`です。
最初はなんでこんなファイル作らなきゃならないのかわからなかったのですが、たくさんフォームを作るのなら明らかに効率がいいですね。あと、データベースに保存する時も便利みたいです。

## データベースに保存する

このままでは『投稿』ボタンが押された時、エラーになってしまいます。
なので、`views.py`にメソッドがpostの場合の処理、すなわちデータベースに保存する処理を書きましょう。

```python:posts/views.py
class WriteView(View):
    def get(self, request, *args, **kwargs):
        return render(request, 'posts/write.html', {'form': WriteForm})

    def post(self, request, *args, **kwargs):
        # formに書いた内容を格納する
        form = WriteForm(request.POST)
        # 保存する前に一旦取り出す
        post = form.save(commit=False)
        # 保存
        post.save()
        # indexのviewに移動
        return redirect(to='posts:index')


write = WriteView.as_view()
```

これでデータベースに保存できるようになりました。
次に保存した投稿を投稿一覧で表示していきます。

# 投稿一覧画面

### 流れ
1. views.pyを作成
2. htmlを作成

```python:views.py
class IndexView(View):
    def get(self, request, *args, **kwargs):
        # Postsテーブルのデータを全て取得
        queryset = Posts.objects.all().order_by('-created_at')
        # 値付きでpost.htmlに飛ぶ
        return render(request, 'posts/post.html', {'posts': queryset})


index = IndexView.as_view()
```
ちなみに`'-created_at'`と、『-』をcreated_atの前につけることで降順にデータを取得します。
結構大事。

```html:templates/posts/post.html
{% extends "base.html" %}
{% block page_title %}post{% endblock %}
{% block title %}Posts{% endblock %}
{% block content %}
    {% for post in posts %}      ←投稿の格納された配列postsをpostとして使う
        <div class="post">
            <p class="text">{{ post.text }}</p>
            {{ post.created_at }}
            <hr>
        </div>
    {% endfor %}
{% endblock %}
```
これで一覧画面を見てみると
<img width="909" alt="スクリーンショット 2019-11-06 2.40.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519379/67f76fbb-19cc-bf62-deac-f36e40acff7c.png">

やっと完成です〜(^○^)
非常にシンプルなコードですが、一応一通り実践してみました。
まだまだ機能拡張の余地があるのでぜひ広げてみてください。