0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

djangoチュートリアルがわからない人のための読むと勇気が出るポエム②-2 Django Database API と管理画面

Posted at

前回の続きですが、チュートリアルとはちょっと順番を変えてやっていきます。  
  
Djangoには、デフォルトで管理者用のインターフェースが用意されています。データベースに直接変更を加えたりするのに便利な機能です。

では最初に、adminとしてログインするためのユーザーを作成しましょう。こういう系のお願いごとは誰に願いするんでしたっけ。

python manage.py createsuperuser

そう、manage.py先輩でしたね。
ここでユーザーのemailアドレスやユーザー名、パスワードなどを入力していきます。(こういう勉強用に急に作ったパスワードとかって忘れがちなので、ほんとはよくないですが、.gitignoreとかで退避してパスワード用のファイルを作るのがおすすめ)
Superuser created successfully.
と出たらユーザー作成成功です。

adminサイトを見てみよう

mysite/urls.pyを見返してください。作成したpollsのurlパターンのほかに、デフォルトでadminというurlが書いてあります。
では、書いてある通り、runserverして、
http://127.0.0.1:8000/admin
にアクセスしてみましょう。ログイン画面が出てくるので、先ほど作成したユーザー情報を入力しましょう。

img.png

ログインボタンを押すと、管理画面が表示されます。
img_1.png

pollsアプリを編集してみよう

管理画面を見ても。pollsアプリを編集できそうなボタンが見つかりません。それができるようにするには、pollsの中のadmin.pyに対して、「Questionモデルをadminで編集したいよ」ということを伝えてあげる必要がありますので、admin.pyを編集していきます。

polls/admin.py
from django.contrib import admin

# quiestionモデルをインポート
from .models import Question

# モデルをadmin管理画面に登録
admin.site.register(Question)

すると、pollsアプリのquestionモデルが表示されているはずです。
img_2.png

当然といえば当然なんですが、中は空っぽです
img_3.png

この画面から編集・追加もできるのですが、先にPYTHONコンソールから追加する方法を紹介します。チュートリアルの apiで遊んでみる のところに戻ります。

Django Database APIで、コンソールからモデルを操作

チュートリアルでいきなり「遊ぶ」とかっていわれてもなんのこっちゃ??ってなりません?ここでは、前回作ったQuestionモデルとChoiceモデルにいろんあデータを追加・変更を行うことをさしています。
では早速コンソールに入って行きましょう。django内部の環境変数にアクセスするためには、以下のようにしてコンソールに入ります。

python manage.py shell

このページを読んでいただいている方の中には、コンソールでpythonを打つことに慣れていない方も多いと思うので、読みながらご自分で打ってみて、一行づつ見比べてみるのがおすすめです。

まず、pollsアプリから、これから操作する予定のモデルをインポートしましょう。また、questionクラスには question_text と pub_date というプロパティがあったのを思い出してください。pub_date用に、timezoneをインポートします。

from polls.models import Choice, Question
from django.urils import timezone

まだなんの質問文も用意していないので、↓のように打つと、こんな感じで出力されます。

Question.objects.all()
# <QuerySet []>

では、最初の質問文と時間を登録していきましょう。
キーワード引数で各データを登録した後に、sava() メソッドを明示的に実行します。(ここでいう「明示的(explicitly)」は、「自動的にはやってくれないから、手動で、『savaしますよ!』っていうのを示さなあかんよ!」って感じの意味です。対義語としては「暗黙的(implicitly)」というのがあり、こういう系のドキュメントでよく出てくる言葉です)

q = Question(question_text="新着情報", pub_date=timezone.now())
q.save()

これでデータベースに登録されたので、idが付与されています。確認してみましょう。

q.id
# 1

それぞれのデータを出力してみましょう。

q.question_text
# '新着情報'
q.pub_date
# datetime.datetime(2023, 7, 4, 12, 6, 33, 301712, tzinfo=datetime.timezone.utc)

おお、なんかうまく行ってそう

と思ったところで、次のコードを打ってみましょう。Questionモデルのデータを全て(all)出力しようとしています。

Question.objects.all()  
# <QuerySet [<Question: Question object (1)>]>

うーん、これだとIDが出力されるだけで、どんなデータだったかちょっと分かりづらい!たのむぜDjango兄さん、ということで、models.pyを編集して、どんなデータだったかちゃんと出力されるようにしたいです。pythonコンソールで
quit()
と打って、コンソールを抜け出しましょう。
問題です。Questionモデル(と、ついでにChoiceモデルを編集するには、どのpythonファイルを編集すればいいでしょう?













正解は、polls/models.py ! これがわかれば、なんとなくではあってもdjangoの構造がわかってる証拠です!アヤしい人は、前回までの記事を560000回読んで、ついでに全部にイイねしてください笑
Questionクラスとchoiceに、__str__(self) というメソッドを追加します。

from django.db import models


class Question(models.Model):
    # 追加
    def __str__(self):
        return self.question_text


class Choice(models.Model):
    # 追加
    def __str__(self):
        return self.choice_text

この__str__(self)メソッドですが、pythonコンソールだけでなく、先程作成した管理画面でに表示する情報を決めて、レコード(データ)を判別しやすくする効果があります。
pythonコンソールから戻ってきたついでに、Django先輩はもう一つ機能を追加したいみたいです。全くもう、しょうがないなぁ

models.py

# 追加
import datetime

from django.db import models

# 追加
from django.utils import timezone


class Question(models.Model):
    # 追加
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

何を追加したか、おわかりでしょうか。was_published_recentlyにアクセスがあったときに、python標準のdatetimeモジュールと、djangoのdjango.urils.timezoneモジュールを使って、記事が投稿されたのが一日前の時間より最近の時間か(=一日以内にとうこうされたか)を確認する機能です。
ではでは、pythonコンソールに戻っていろいろ打ってみましょう。まずは先程のコードの出力がどうなっているか確認します。

>>>from polls.models import Choice, Question
>>>Question.objects.all()
# 新着情報

OK!models.pyでquestion_textが返されるように書いたので、うまく行ってます!管理画面でどうなってるか気になるところですが、せっかくpythonコンソールにいるので、いろいろAPIで「遊んで」みましょう!
DjangoのデータベースAPIは、そのメソッドとキーワード引数の組み合わせによって、様々な形の出力を得ることができます。 その内いくつかは、もともとのキーワード引数(question_text, pub_date)に**ダブルアンダースコア(__)**をつけたものです。

IDによるフィルタリング

>>> Question.objects.filter(id=1) 
<QuerySet [<Question: 新着情報>]>

「新着」という文字で始まるquestion_textを検索
question_textに、__startswithをつけます

>>> Question.objects.filter(question_text__startswith="新着")       
<QuerySet [<Question: 新着情報>]>

pub_date__yearをつかって、今年投稿されたものを表示してみましょう

>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: 新着情報>

ところで、存在しないIDでフィルタリングするとどうなるでしょう?ものは試しです。

>>>Question.objects.get(id=2)
# polls.models.Question.DoesNotExist: Question matching query does not exist.

ですよね~

ここからはちょっとだけSQLの知識が有るとわかりやすいです。「SQLなんて全く触ったことないぜ!」ていう方は、youtubeとかでSQL講座みたいなのをチラ見しておくといいかも!

データベースでは主キー(=プライマリキー)というのがあります。データベースのレコードを識別するための、重複しないデータが入ったカラムのことです。
たとえば、社員氏名と部署名、社員番号が書かれたテーブルがあるとします。このうち、絶対に重複しないのは社員番号ですよね。同姓同名のひとがいるかもしれませんし。この場合、社員番号が主キーとなります。
今回の場合は、自動生成されるIDが主キーとなっていますが、常にID=主キーとは限らないので、注意が必要です。
以下のコードを打ってみましょう。引数のpkはペナルティーキック、ではなくPrimary Keyの略です。

>>> Question.objects.get(pk=1) 
<Question: 新着情報>

では、いままでQuestionモデルしか操作してこなかったので、Choiceモデルにもデータを挿入していきましょう。
質問に対する選択肢(Choice)を作成しているので、先程pk=1と指定して出力された質問に対し、その質問に対する複数の選択肢を用意していきます。
まず、先程出力された内容("新着情報")を、変数に格納します。

q = Question.objects.get(pk=1)

ここで、これから作る予定の choice_set というオブジェクトの中身を表示してみます。何を言っているか分からねえと思うが、おれも何をしているのかわからねえ!だってオブジェクトがないんだから!(あ、ちなみにポルナレフでした)

q.choice_set.all()
# <QuerySet []>

エラーじゃなくて、[]が返ってくるのがミソです。

ここで、models.pyを見返してみましょう。Choiceモデルはどんな感じになってたでしょうか。

models.py
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def __str__(self):
        return self.choice_text

プロパティを見てみると
・question: Questionモデルの外部キー
・choice_text: 文字列
・votes: 整数
となっています。

では、choice_setオブジェクトの中身をつくっていきましょう。今回は選択肢を作るので、Choiceモデルのquestion, choice_text, モデルのなかみを作るには、SQLを発行する必要があり、カラムを作成するにはcreate文を発行します。Djangoでcreate文はこのようにして書くことができます。

q.choice_set.create(choice_text="まあまあ", votes=0) 
q.choice_set.create(choice_text="サイコー", votes=0) 
q.choice_set.create(choice_text="ハックしてるぜ", votes=0)

※チュートリアルその1では質問が「what's new(最新情報)」となっていたのが、その2では「what's up(元気?)」になってます。しかも、choiceのふたつめで,whats upにたいして "the sky"とかっていうアメリカンジョークをいれてます。まったく、こういうわかりにくいことやめてほしいもんです。
それはいいとして、3つの選択肢が入ったので、早速表示してみましょう。

>>> q.choice_set.all()
<QuerySet [<Choice: まあまあ>, <Choice: サイコー>, <Choice: ハックしてるぜ>]>
>>> q.choice_set.count()
3

DjangoのAPIは自動的にリレーションに従ってくれます。そして、引数にダブルアンダースコア(__)をつけて各モデルのプロパティやメソッドにアクセスできるので、こんなこともできます。

# 今年投稿されたものだけフィルタリング  
>>> Choice.objects.filter(question__pub_date__year=current_year)  

# 「ハック」ではじまるchoice_textを削除
>>> c = q.choice_set.filter(choice_text__startswith="ハック")
>>> c
<QuerySet [<Choice: ハックしてるぜ>]>
>>> c.delete()
(1, {'polls.Choice': 1})
>>> q.choice_set.all()  
<QuerySet [<Choice: まあまあ>, <Choice: サイコー>]>

管理画面を確認してみよう

せっかくデータも用意できたので、管理画面で確認してみましょう.
※せっかくなので、質問文を「元気?」と変えておきます。

img_4.png


今回はここまで。次はチュートリアルその3に入ります。
ではでは!

0
2
0

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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?