the dawn of yuriko hisory

アニメやら漫画関係で何か作りたいものと勉強したことのメモ用

DjangoでミリオンライブキャラクターDBを作成 ~個別ページの作成~

現在までの完成形

現在までの完成形
https://i.gyazo.com/b980fabf75df0e29f5741060cff65f90.png

個別ページのViewの説明

def detail(request, pk):
    idol = get_object_or_404(Idol, pk=pk) //1
    return render(request, 'mysite/detail.html', {'idol' : idol} )

1. 基本通りにDBのプライマリキーからアイドルの情報を取得しています。
アイドルの名前から取得するように変更した方がURLとしてもいいとは思うのですが、
そこまでの必要性はないかなと思いデフォルトのpkにしています。

個別ページのテンプレートの説明

{% extends 'mysite/base.html' %}

{% block content %}
  <div class="row">
    <div class="image col-md-4">
      <img src="{{ idol.image.url }}" class="img-responsive"/> <!-- 1 -->
    </div>
    <div class="detail col-md-8">
      <table class="table table-bordered">
        <tbody>
          <tr>
            <td><strong>名前</strong></td>
            <td>{{ idol.name }}({{ idol.yomigana }})</td>
          </tr>
          <tr>
            <td><strong>誕生日</strong></td>
            <td>{{ idol.birthday }}</td>
          </tr>
          <tr>
            <td><strong>身長</strong></td>
            <td>{{ idol.height }}cm</td>
          </tr>
          <tr>
            <td><strong>声優</strong></td>
            <td>{{ idol.cv }}</td>
          </tr>
        </tbody>
      </table>
      <p class="h2">詳細</p>
      {{ idol.detail }}
    </div>
  </div>

{% endblock content %}

1. 前回モデルで作成したImageFieldのurlを使うと格納されているフォルダのアドレスをそのまま渡してくれるので
imgタグにそのまま入れるだけで表示ができました。

classのimg-responsiveはBootStrapのクラスで、
画像ファイルをレスポンシブ対応にしてくれています。
これのおかげで画像をレスポンシブにしてくれるので、表示がキレイにできます。

テーブル内の表記については、特別難しいことはしていなくて、
Viewから渡された値を表示しているだけです。

次やること

個別ページは現段階ではこの状態で完成形として
(他にやることといえばモデルの修正と実際のデータを入力するだけなので)
Indexページで初期表示に全件のアイドルを取得できるようにしてみましょう。

ゼロから作るDeep Learning 始めました。

ディープな世界へ

もともとAIに興味を持ってエンジニアとして働き始めました。
気が付けばそのためにPythonを始めたというのに
Python自体が好きになってDjangoで何か作ろうとかしている有様です。

もともとWEB側にも興味はあったので今の現状に不満があるわけではないのですが
やはり最終的な目標は自身でAIの作成です。
AIがってわけではなくかわいいアイドルたちを具現化したいだけですけどね。
そのための手段がたまたまAIだっただけです。

そんな話はさておき先週の土日からずいぶんと話題になって時間が経ちましたが
ゼロから作るDeep Learningを読み始めています。
数学の勉強をほぼしてこなかったため、数式をみると頭が…

目標としては8月14日にTensorFlowの本が出るのでそれまでに読み進めて
そこからTensorFlow本を読みふけりたいなーと思っております。

今後はブログでも書評を書いていくのもいいかもしれません。
読まないで積んである本を読むキッカケが欲しいです。

埼玉スーパーアリーナ

タイトルにまったく関係ありませんが、もう一週間後には埼玉スーパーアリーナでシンデレラガールズのライブがあります。
私は2日目の8月13日に参戦いたします。
最近はもっぱらミリオンPですが、やはりライブは楽しみです。
早く響子ちゃんに会いたいものです。

チケットが届いたのでテンションがあがってしまいこんな記事になってしまいました。
申し訳ございません。

DjangoでミリオンライブキャラクターDBを作成 ~モデルの作成~

アイドル用のモデルを作成


以下models.py

from django.db import models

class Idol(models.Model):
    name = models.CharField(max_length=50)
    yomigana = models.CharField(max_length=50)
    height = models.IntegerField()
    threeSize = models.CharField(max_length=20)
    birthday = models.CharField(max_length=20)
    cv = models.CharField(max_length=50)
    detail = models.TextField()
    image = models.ImageField(upload_to='images/')

    def __str__(self):
        return self.name

今回はアイドルDBなのでとりあえずそれっぽい情報だけ入れられれば良いです。
完成してから必要があれば3サイズ順に並べたい!とかになりそうなので
3サイズを分けて検索できるようにしたりとかまあ色々とごにょごにょしたくなりそうですが。

新たに学習したこととしては
ImageFieldでしょうか。
settings.pyの方で

MEDIA_ROOT = os.path.join(BASE_DIR, 'media') #追加
MEDIA_URL = "/media/" #追加

こいつらを追加して置くと、あとは管理サイトで画像を保存すると
/media/imagesに画像を置いてくれます。
非常に便利!だと思いきや、管理サイトに画像を表示しようとして手が止まっています。
後はフォルダに入ったはいいけどこれテンプレートからちゃんと取得できるのかな?といったところです。

管理サイト画像
https://i.gyazo.com/ac8d5e2bbbf2d023800d74e14444eeda.png


次やること

今回作るのは簡易的なデータベースなので
モデルさえできてしまえばあとは簡単な気がします。
画像さえ取れれば…
とりあえず次は個別ページを作って画像をしっかりと取得できるかを作成してみます。

DjangoでミリオンライブキャラクターDBを作成 ~prologue~

目的

DjangoGirlsを終えた段階で作れそうなものを実際に作成していく。
あと個人的にキャラクターまとめを作りたかっただけ ←ここ重要


どんなサイトを作るのか

画面は2枚

メインページ
・検索フォーム
・キャラクター一覧

個別ページ
・キャラクター画像
・キャラクター説明

これだけです。
いきなり難しいページつくってもね?


必要になりそうな知識

メインページ
・検索フォーム
ここが一番の難関ですかね。
できればAPI作成して飛ばしてViewModelで画面は弄るようになんかがよさそうですが
そうなってくるとJavaScriptでもVueかReactあたりを学ぶ必要がありそうです。
とりあえずは一番最後に回すことになるでしょう。

・キャラクター一覧
これは初期表示時は全件表示させるので
まずはそこだけを実装しましょう。
後は検索フォーム時に色々いじることになります。

個別ページ
・キャラクター画像
公式のを引っ張ってきます。著作権とか色々気にしたらアウト

・キャラクター説明
これはモデルを作って管理サイトで投稿したものを表示させるだけです。
あとはレイアウトはHTMLとCSSでごにょごにょしましょう。


作成期間

一カ月までかけたくはないかなーと思っています。
ですが検索フォームをどうするかによりますね。

その他

テストは今のところ作成するつもりはないです。
ただ、今後実際に作成する際にはなるべく書いていく方が良いかとは思っているので
どこかのタイミングでテストコードの書き方も勉強していきます。

作成したものはデプロイまでやりたいですが公開する必要があるのかどうかはわかりません。
コードはGitHubにあげる予定です。
コードの修正事項などあったらどんどんお願いします。


とりあえず簡単になりましたこんな感じで1個目のサイトを作っていきましょう。

DjangoGirlsを終えて次へ

終えてみた感想

少し前に一度さっとやりましたが、
ブログで書くということで一行一行理解するようにやっていきました。
思っていた以上にわかっていなかった部分も見つかり今後もまだまだ学習し続けていかなければなと
チュートリアルとしてのDjangogirlsは非常に優秀なので
ぜひともDjangoに興味を持ち実践する人が増えるといいなと思っております。

次やること

Django Girlsの続きがあります
Introduction · Django Girls Tutorial: Extensions
ですが、全部英語でここまで必要あるのかなーと少し思っているので
一度ここでDjango Girlsでやったことの範囲で簡単なサイトを作成していこうかなと
公式のチュートリアルを触るのもいいんですけどね。

何を作るか

一般的に言語学んだあと作るものと言えばTodoアプリとかが多い気がします。
ですが、あくまでこのブログの方針といいますが
自分がプログラミングをやる方向性は
>アニメやら漫画関係で何か作りたいもの
になるのでそういったもので考えていく方向です。

作るものについては別記事で簡単にまとめていきます。

DjangoGirlsに挑戦 ~フォームを作ろう~

フォームで作ろう

今回で最後です。頑張ります。

Djangoフォーム

フォームを作成していきます。
デフォルトではフォーム用のファイルが作成されていないので作成していきます。

app
└forms.py #追加


以下forms.py

from django import forms //1
from .models import Post

class PostForm(forms.ModelForm): //2

    class Meta: //3
        model = Post
        fields = ('title', 'text',) //4

1. Djangoに実装されてるフォームクラスをインポートします。

2.今回はモデル用のフォームを作成するためにModelsFormを利用しています。
Modelと結びつくためのフォームを作成する際は記述します。

3. class Metaはクラス内の設定を書いていく所の認識をしています。
PostFormクラス内でどういった設定をしていくのかを以下に書いていっています。

4.fieldsはmodelで指定したPostの中のどのフィールドをフォームで使用するのかを指定しています。
今回はタイトルとテキストを指定しています。

フォーム画面の表示

投稿用のページへのリンクをbase.htmlに置きます。

{% load staticfiles %}
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" >
<link href="http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="{% static 'css/blog.css' %}">
</head>
<body>
  <div class="page-header"> 

    <!-- 追加 -->
    <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
    <!-- ここまで -->

    <h1><a href="">the dawn of yuriko hisory</a></h1>
  </div>
  <div class="content container">
      <div class="row">
          <div class="col-md-8">
              {% block content %}
              {% endblock %}
          </div>
      </div>
  </div>
</body>
</html>

class指定については特にきにしなくて良いです。
次にURLを作成します。

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^$', views.post_list),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^post/new/$', views.post_new, name='post_new'), //1
]

1.投稿ページのURLは一意でいいのでpost/new/へのアクセスになってます。
それ以降はいままでと特別変わりませんね。

urls.pyで指定してpost_newをViewで作ります。

from .forms import PostForm

def post_new(request):
    form = PostForm() //1
    return render(request, 'blog/post_edit.html', {'form': form})

1.ここで作成したフォームオブジェクトをテンプレートに渡してあげています。

最後にテンプレートを作成します
以下post_edit.html

{% extends 'blog/base.html' %}

{% block content %}
    <h1>New post</h1>
    <form method="POST" class="post-form">{% csrf_token %} //1
        {{ form.as_p }} //2
        <button type="submit" class="save btn btn-default">Save</button>
    </form>
{% endblock %}

1.formタグ
method="POST" はリクエストにPOSTメソッドを利用することを明示しています。
{% csrf_token %}は CSRF対策です。
CSRFについては別で調べる必要がありますが、
とにかくDjangoではフォーム利用時にはCSRF対策をしないとエラーが発生するので
必ず書きましょう。
ちなみにAjax処理を行う際にもCSRF対策をしないといけないみたいです。
そのうちAjaxを使った処理も行いたいです。

2.as_pは

タグでフォームを作成することを示しています。
画像のような形で出力されます。
as_ulやas_table等もありますし
細かくフォームを設定したければ普通にformから値を持ってくればいいですし
中々Djangoのフォームは便利です。
https://i.gyazo.com/d0b68d06d2d8f7fb146ce598ecb6d569.png


とりあえずこれでフォームページができました。
https://i.gyazo.com/33d9a4a9004c049c4e7b51f4776d780c.png

こんな感じになります。

POST処理

ここまでで表示はできましたが、投稿処理ができていません。
フォームを保存する処理を作成していきます。

ここで作成したViewのpost_newを修正していきます。

from django.shortcuts import redirect

def post_new(request):
    if request.method == "POST": //1
        form = PostForm(request.POST) //2
        if form.is_valid(): //3
            post = form.save(commit=False) //4
            post.author = request.user //5 
            post.save() //6
            return redirect('post_detail', pk=post.pk) //7
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

1. フォーム側でHTTPリクエストをPOSTに設定していました。
もしフォームからリクエストが送られた場合はPOSTになるので以下の処理を
初期表示時はGETが送られるのでelse以下で先ほどまでと同じ処理を行います

2. PostFormのPOSTされた値をformに渡しています。
https://i.gyazo.com/fedf63e08516fdfda5a6709f77c32d7d.png

3.is_valid()はそのままバリデーションの意味です。
ただ、バリデーションの設定はしていませんでしたね。
ですが、Postモデルで指定したものが適用されるので
未入力で送信してみるとエラーが起こります。
今回はバリデーションメッセージなどの細かい部分については触れていません。

4.form.save(commit=False)はコミットせずにPostモデルをpost変数にいれています。

5.Postモデル内のauthorにリクエストを送っているユーザーの値を設定します。
このrequest.userはどこの情報なのかがイマイチわからないです。

6.PostモデルをDBにコミットします。

7. リダイレクトで今回作ったページへと遷移します。
動き自体はわかると思います。

フォームの編集

最後に既存のものを編集するページを作成します。

個別ページ用のpost_detailに実装します。

{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.author %}
            <div class="date">
                {{ post.author }}
            </div>
        {% endif %}

        <!-- ここに追加 -->
        <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
        <!-- ここまで -->

        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaks }}</p>
    </div>
{% endblock %}

urlsの修正

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^$', views.post_list),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
    url(r'^post/new/$', views.post_new, name='post_new'),
    url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'), #追加
]

viewの修正

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

フォーム作成とほぼ同じです。
今までやったことができていれば難しくありません。


以上をもってdjangogirlsは終了になります。
今後の予定については別の記事で書いていきます。

DjangoGirlsに挑戦 ~アプリケーションを拡張しよう~

アプリケーションを拡張しよう

今回は個別の記事の表示
URLパターンをここで覚えておくとサイト作りに役立ちそう

リンクの作成

post_list.htmlにリンクをはっつけます。

% extends 'blog/base.html' %}

{% block content %}
  {% for post in posts %}
    <div class="post">
      <div class="date">
        書いた人:{{ post.author }}
      </div>
      <h1><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1> //1
      <p>{{ post.text|linebreaks }}</p>
    </div>
  {% endfor %}
{% endblock content %}

1. {% url 'post_detail' pk=post.pk %}
前半部分はpost_detailのリンクだとみてわかると思います。
pk=post.pkは変数の値を渡しています。
詳しくはURLとView側を見ていくとわかります。

とりあえず今の状態でアクセスしてもpost_detailがないので
エラーが起こってしまいます。
post_detailを作成します。

まずapp/ulrs.pyを修正します。

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^$', views.post_list),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'), //1
]

1.post/までは以前までで理解できます。
(?p[0-9]+)について
?pで変数宣言 pkを受け取ります。
post_list.htmlであったpk=post.pkの値がここに入るわけですね。
[0-9]+については正規表現がわかればある程度理解できると思います
0~9の数字のみで +が一けた以上を表しています。
つまりURLは (省略)/post/5 といった形になります。


URLのパターンができたので、次はView側を作成します。
views.pyに以下メソッドを記述します。

from django.shortcuts import render, get_object_or_404

def post_detail(request, pk): //1
    post = get_object_or_404(Post, pk=pk) //2
    return render(request, 'blog/post_detail.html',{
        'post': post
        })

1.pkは先ほどから出ている変数の値です

2. get_object_or_404はオブジェクトが存在しなかった場合404エラーを返すようにしています。
第一引数に取得するモデル、第二引数に検索する値を入れているので(Post, pk=pk)になっています。
ここでpkで検索していることに疑問を思うかもしれません。(どこかででてたかな?)
pkはDB作成時ににDjango側が自動的に主キーとなるカラムを追加してくれています。
pk=primary keyですね。
なのでそれを使って今まで検索していたのです。

さて、最後にテンプレートの作成をします。
これを作らないと画面表示できませんしね。
post_detail.htmlを作成します。

 extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.author %} //1
            <div class="date">
                {{ post.author }}
            </div>
        {% endif %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaks }}</p>
    </div>
{% endblock %}

拡張テンプレートを忘れずに使用しましょう

1.{% if %} {% endif %}について特別説明の必要はない気がしますが
データがあれば出力して、空欄なら何もif文内の処理はおこないません。
意外とテンプレート側でもifを使うことが多いので慣れるとよさそうです。

以上で画面の表示も完璧になりました。
自称で入力フォームを作成してDjangogirlsは終了です。