LoginSignup
42

More than 5 years have passed since last update.

PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(5)【Django shellでDB操作入門編】

Last updated at Posted at 2016-11-11

解説記事の構成

No. タイトル
1 PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(1)【環境構築編】
2 PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(2)【プロジェクト作成編】
3 PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(3)【アプリケーション作成・DB設定編】
4 PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(4)【ルーティング設定・MTVデザインパターン入門編】
5 PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(5)【Django shellでDB操作入門編】
6 PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(6)【MTVデザインパターン完成編】

開発環境

  • OS: Mac OS Sierra (10.12)
  • Python 3.5.2

Macの環境を前提として話を進めていきます。

Pythonのバージョン確認は以下の通りです。

$ python3 --version
Python 3.5.2

Django shell

今回は Django shell の使い方を紹介します。

前回は、Django adminを使って、DBを操作したり確認したりする方法を紹介しました。
Ruby on Railsに慣れている方は、そんなのコンソールの rails c で操作したり確認したりすれば良いんじゃないの?と思われる方もいらっしゃると思いますが、その通りかと思います。
Djangoもそういったコンソールを備えており、それが Django shell というわけです。

Django shellを使ってみよう

まず、Django shell を立ち上げます。

Djangoの起動
$ python3 manage.py shell
Python 3.5.2 (default, Jun 29 2016, 13:43:58) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 

Django shellでデータを表示させよう

では、早速定義したモデルである Post のデータを見てみましょう。

>>> Post.objects.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'Post' is not defined

残念ながらエラーが出てしまいました(Ruby on Rails同様の手順でならエラーは出ないのに)。
Djangoでは、最初にモデルをインポートしないといけないようです。

>>> from blog.models import Post
>>> Post.objects.all()
<QuerySet [<Post: サンプル記事のタイトル>]>

これでDB内のデータを確認することが出来増しtあ。
QuerySet という名前が出てきていますが、クエリセットとはモデルが提供しているオブジェクトのリストのことだそうです。

Coffee Break:DjangoとRuby on Railsを比べてみる

これまでの記事を読まれている方はお気づきかも知れませんが、私は Ruby on Rails を一番最初のWebフレームワークとして学習し、それが自分の中のスタンダードになっているため、Djangoはところどころで、Ruby on Railsに比べると使いにくいなという印象を受けています。
しかし、機械学習を使用するためには、PythonのWebフレームワークは非常に魅力的です。
個人的には、Ruby on RailsでWebアプリケーションの土台を作り、DjangoでWeb APIを作るのがオススメです。

Django shellでobjectを作ろう

データベースに新しい Post を作成します。

>>> Post.objects.create(author=ryosuke, title="ryosuke's article", text="これはQiita用の記事です")
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'ryosuke' is not defined

エラーが出ましたね。
author=ryosuke でエラーが起きました。
author って指定した名前で勝手に増えるものではないのですね。。。

このあたりは、実は Django でモデルを作った際(PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(3):モデルの作成)に、 blog/models.py 内で

blog/models.pyの一部
author = models.ForeignKey('auth.User')

として、Userモデルを参照するように設定しているためです。
ここを単純に文字列として定義しておけば、新規の名前に対しても問題なくオブジェクトを作成できるというわけです。
しかし、これではユーザーの名前の管理が難しくなるので、ユーザーはユーザー、ポストはポストとして管理して、ポストからユーザーを参照するようにしています。

今回は新しくユーザーを作ることはせず、ryosuke というユーザーに admin の情報を与え、そこから新規オブジェクトを作成していきます。

ryosukeにadminの情報を与える
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: admin>]>
>>> ryosuke = User.objects.get(username='admin')
>>> ryosuke
<User: admin>
Postに新規オブジェクトを作成
>>> Post.objects.create(author=ryosuke, title="ryosuke's article", text="これはQiita用の記事です")
<Post: ryosuke's article>

これで上手くいきました。
Postのオブジェクトリストを見てみましょう。

>>> Post.objects.all()
<QuerySet [<Post: サンプル記事のタイトル>, <Post: ryosuke's article>]>

新しいPostが増えていることが分かると思います。

Django shellで特定条件のオブジェクトを抽出しよう

特定条件を抽出する場合は all() であった部分を filter() を使い、引数にプロパティの情報を与えます。
例えば、author=ryosuke のPostのみ抽出する場合は以下のようになります。

>>> Post.objects.filter(author=ryosuke)
<QuerySet [<Post: サンプル記事のタイトル>, <Post: ryosuke's article>]>

今の所、全てのオブジェクトと変わりがありませんが、authorが増えてきた場合は、このようにして、著者ごとにわけることができます。

完全に一致する条件の抽出だけでなく、一部に特定の文字列を含むような部分一致の検索もできます。

titleにarticleを含むオブジェクトのみ抽出
>>> Post.objects.filter(title__contains='article')
<QuerySet [<Post: ryosuke's article>]>

title__contains を付け加えることで、部分一致も上手く扱えるようになります(これ結構便利です)。

Pythonでは、上記の用にアンダーバーが2つ続くことがよくあります。
参考:Django Girls Tutorial:クエリセット1

Note
title と contains の間に、アンダーバーが2個続いていますが、これはDjangoのORMの構文です。フィールド名のtitleと、照合タイプのcontainsを、2つのアンダーバーで連結させています。もしアンダーバーが1個だけだと、title_contains というフィールド名だと判断されてしまい、エラーになります。("FieldError: Cannot resolve keyword title_contains")

つぎに、これもよく使う機能ですが、既に公開済みの記事のみを抽出する方法です。
Qiitaでも記事の作成はしますが、下書きで一旦置いておく場合ありますよね。
この現時刻で、公開済みのみを抽出したい場合の方法です。

>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: サンプル記事のタイトル>]>

勘の鋭い方ならお分かりかもしれませんが、lte の部分が contain 同様、フィルターを書ける際の条件分になっています。
lteless than or equal toの略で、数学的な記号では 「published_date <= 現時刻」ということになります。
現時刻より前もしくは現時刻と一致した場合は抽出するといった条件分ですね。
先ほどDjango shellから追加したオブジェクトは published_date を設定していなかったので、今回の条件には該当せずとなっています。

変数名にはひとつのアンダーバーを使うことが多い為、DjangoのORMの構文にはアンダーバー二つ続きを採用しています。アンダーバーが一つだと変数名として扱われてしまうため"FieldError: Cannot resolve keyword title_contains"エラーとなります。

オブジェクトの内容を更新

さきほど作成したオブジェクトがまだ公開 (publish) されていなかったので、これを公開していきましょう。

作成したモデルの取得
post = Post.objects.get(id=2)
>>> post
<Post: ryosuke's article>

blog/models.pypublish() メソッドを以下のように定義しているため、このメソッドを使えば、簡単に published_date の値を更新することができます。

blog/models.py
def publish(self):
    self.published_date = timezone.now()
    self.save()

では、このpublish()メソッドを使っていきます。

>>> post.publish()
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: サンプル記事のタイトル>, <Post: ryosuke's article>]>

これで、無事記事を公開することが出来ました。

オブジェクトのリストの並べ替え

最後に簡単に並べかえの使い方を知っておきましょう。
Webページでは、金額や日時による並べ替えをすることが多々有り、よく使うコマンドになると思います。

並べ替えには order_by() を使用します。

>>> Post.objects.order_by('created_date')
<QuerySet [<Post: サンプル記事のタイトル>, <Post: ryosuke's article>]>

基本的には、日時であれば古い順に並びます。
新しく追加した順に並び替えたい場合は、この逆順を以下のように指定すればできます。

>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: ryosuke's article>, <Post: サンプル記事のタイトル>]>

なんと、order_by の引数に - を付けるという発想。
ascdesc ではないのですね(たぶんこの辺りもサポートしてると思いますが)。

これで並べ替えも出来るようになりました。

Django shellの終了

コンソールを立ち上げたものの、最初は終了の仕方がよく分からないといったことがあります。

>>> exit()

この最後の () もお忘れ無く。

次回の解説記事

PythonのWebアプリケーション(Django)を初心者にもわかりやすく解説(6)【MTVデザインパターン完成編】

参考文献

おまけ

フォローお待ちしています!

サービス紹介
「数学→プログラミング→Webアプリケーション」まで一気に学べる機械学習のマンツーマン家庭教師サービス「キカガク」に興味のある方はお気軽にご連絡ください。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42