自分のツイートだけを保存していく不毛なTwitter投稿クライアント

#自分のツイートだけを保存する

結局のところ何のために利用するかはわからないですが、Djangoのフォーム・テンプレートなどの理解を進めるにはやっぱりTwitterAPIで遊ぶのが最適解なのではないかなと思っています。というか何回Twitter APIで遊ぶんだよ、っていうのはやめてください。自覚症状はあります。

#Djangoプロジェクトを作成する

Python3.6を想定しているので仮想環境構築は楽するやつ。

```shell-session
$ python3 -m venv pyworks
$ ls pyworks/
$ . pyworks/bin/activate
```

既にDjangoがインストールされているものとして話を続けます。

```shell-session
(pyworks)$ pip install requests requests_oauthlib
(pyworks)$ cd pyworks
(pyworks)$ django-admin startproject tweetsave
(pyworks)$ cd tweetsave
(pyworks)$ python manage.py startapp myapp
```

ひとまず準備完了ですが、Twitter APIのキーなどは取得しておいてください。

#各種基本ファイルの編集

settings.pyの最終行あたりを以下のように書き（替え）加えます。メディアに関しては書いておいたほうが後が楽だから、という感じなのですっ飛ばしても今回は問題ありません。静的ファイル部分だけ書けばいいかな、とは。

```settings.py
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = True


STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
```

urls.pyも同様で、冗長に書いてますが「メディアファイルの取扱」を今後するかもしれないので書いておこう、くらいの感じです。

```urls.py
from django.conf import settings
from django.conf.urls import url, include
from django.conf.urls.static import static
from django.contrib import admin

urlpatterns = [
    url(r'^myapp/', include('myapp.urls',namespace='myapp')),
    url(r'^admin/', admin.site.urls),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
```

myapp/ にはurls.py が存在しないので新規作成します。


```myapp/url.py
from django.conf.urls import url
from . import views


urlpatterns = [
    url(r'^', views.index, name='index'),
]
```


#モデルの定義

今回はただひたすら自分のツイートをデータベースに保存しますので、シンプルです。

```myapp/models.py
from django.db import models

class MyTweet(models.Model):
    tweet_words = models.CharField(max_length=140)
    created_at = models.DateTimeField(auto_now_add=True)
```


せっかくなので管理画面用も書いておきます。

```myapp/admin.py
from django.contrib import admin
from .models import MyTweet

class MyTweetAdmin(admin.ModelAdmin):
    list_display = ('id','tweet_words','created_at')

admin.site.register(MyTweet,MyTweetAdmin)
```


#フォームの作成

Django Formを利用しなくても全く問題ないんですが、せっかくなのでフォームを書きましょう。特にオプション的な記述はせず、ごくシンプルなフォームを生成しますので、たったこれだけ。

```.myapp/forms.py
from django import forms
from myapp.models import MyTweet


class TweetForm(forms.ModelForm):

    class Meta:
        model = MyTweet
        fields = ('tweet_words',)
        widgets = {
            'tweet_words': forms.Textarea()
        }
```

#ビューを書く

自分で言うのも何ですが、凄く冗長です。

```myapp/views.py
from django.http.response import HttpResponse
from django.shortcuts import render, redirect
from django import forms
from myapp.models import MyTweet
from myapp.forms import TweetForm

from requests_oauthlib import OAuth1Session
import requests
import json

C_KEY = '＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋'
C_SECRET = '＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋'
A_KEY = '＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋'
A_SECRET = '＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋＋'

Post_API = 'https://api.twitter.com/1.1/statuses/update.json'

tw = OAuth1Session(C_KEY,C_SECRET,A_KEY,A_SECRET)

def index(request):
    form = TweetForm(request.POST or None)

    msg = request.POST.get('tweet_words')
    url = Post_API
    params = {'status': msg,'lang': 'ja'}
    req = tw.post(url, params = params)

    if request.method == 'POST':
        if form.is_valid():
            if req.status_code == 200:
                timeline = json.loads(req.text)
                form.save()
                return redirect('myapp:index')

            else:
                contexts = {
                    'Error_message': 'API制限中',
                    }
                return render(request, 'myapp/index.html', contexts)

            return redirect('myapp:index')

    result_text = MyTweet.objects.all().order_by('-id')
    contexts = {
        'form':form,
        'result_text':result_text,
    }
    return render(request, 'myapp/index.html', contexts)
```

#テンプレートを書く

の前に、静的ファイルのディレクトリを再確認。

<img width="609" alt="スクリーンショット 2017-05-16 11.46.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/71585/5e9e7e02-2fa1-2f1a-5812-15e0d7350c14.png">

myapp/templates/myapp/ にテンプレートファイルを配置します。CSSやJS等の場合も同様に、
myapp/static/myapp/css~ などとして配置します。

同一プロジェクト内に複数アプリケーションを配置する場合などに、名前の競合で見つからないよ！を防ぐためです。


```myapp/base.html
<!DOCTYPE html>
	<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
    {% load static %}
    <link rel="stylesheet" href="{% static 'myapp/css/style.css' %}" >
    <link rel="stylesheet" href="{% static 'myapp/css/bootstrap.min.css' %}">
	</head>
	<body>
		{% block body %}
		{% endblock %}
	</body>
</html>
```

```myapp/index.html
{% extends 'myapp/base.html' %}
{% block body %}
<div class="container">
  <div class="row">
    <div class="col-md-12">
      <div class="col-md-4">
        <form action="{% url 'myapp:index' %}" method="post">
            <div class="row">
              {% for field in form %}
              <label>{{ field.label_tag }}</label>
              <label>{{ field }}</label>
              {% endfor %}
              <input type="submit" class="btn btn-primary" value="送信">
              {% csrf_token %}
            </div>
        </form>
      </div>
      <div class="col-md-8">
        {% include "myapp/result.html" %}
      </div>
    </div>
  </div>
</div>
{% endblock %}
```

```myapp/result.html
{% block body %}
<ul class="row">
  {% for i in result_text %}
  <li class="box clearfix">
    <dl>
      <dt> {{ i.created_at }}</dt>
      <dd>{{ i.tweet_words }}</dd>
    </dl>
  </li>
  {% endfor %}
</ul>
{% endblock %}
```

#migrations / migrate

お約束のやつをやります。

```shell-session
(pyworks)$ python manage.py makemigrations myapp
(pyworks)$ python manage.py migrate
```

必要に応じて

```shell-session
(pyworks)$ python manage.py createsuperuser
```

#実行する

runserverして、実行します。

<img width="965" alt="スクリーンショット 2017-05-16 11.51.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/71585/ddc85806-2b97-e6c7-099d-df120adb7261.png">

なんと不毛なアプリケーションの誕生です。