DjangoのDBにMongoDBを使ってみる

django-x-mongodb

Djangoのチュートリアルに従ったPollアプリにdjongoパッケージを使用してMongoDBを導入してみます。
コードはGithub上にあります。
https://github.com/Yosuke-Nishizawa/django-x-mongodb

環境

Python 3.8.5
MongoDB shell version v4.4.2
Django 3.0.5

Pollアプリのベース作成

プロジェクト・アプリの作成

# 仮想環境作成
python -m venv venv
# 仮想環境適用
source venv/bin/activate
# djangoインストール
pip install django
# mysiteプロジェクト作成
django-admin startproject mysite
# pollsアプリを作成
cd mysite
python manage.py startapp polls

pollsアプリをプロジェクトに含める

mysite/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls.apps.PollsConfig',
]

モデル定義

polls/models.py

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


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

djongo導入

インストール

pip install djongo

DB接続情報修正

mysite/settings.py

DATABASES = {
    'default': {
        'ENGINE': 'djongo',
        'NAME': 'poll',
        'CLIENT': {
           'host': 'localhost',
        }
    }
}

DBマイグレーション

python manage.py makemigrations polls
Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice
python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
This version of djongo does not support "NULL, NOT NULL column validation check" fully. Visit https://www.patreon.com/nesdis
  Applying contenttypes.0001_initial...This version of djongo does not support "schema validation using CONSTRAINT" fully. Visit https://www.patreon.com/nesdis
 OK
  Applying auth.0001_initial...This version of djongo does not support "schema validation using KEY" fully. Visit https://www.patreon.com/nesdis
This version of djongo does not support "schema validation using REFERENCES" fully. Visit https://www.patreon.com/nesdis
 OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name...This version of djongo does not support "COLUMN DROP NOT NULL " fully. Visit https://www.patreon.com/nesdis
This version of djongo does not support "DROP CASCADE" fully. Visit https://www.patreon.com/nesdis
 OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying polls.0001_initial... OK
  Applying sessions.0001_initial... OK

DBの確認

mongo
> show dbs

pollが作成されている

poll    0.000GB
> use poll
> whos collections

Question, Choiceに対するcollectionが作成されている

__schema__
auth_group
auth_group_permissions
auth_permission
auth_user
auth_user_groups
auth_user_user_permissions
django_admin_log
django_content_type
django_migrations
django_session
polls_choice
polls_question

モデルを通してデータをやり取りしてみる

わかりやすいように__str__を定義しておきます。
polls/models.py

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return str(self.__dict__)


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 str(self.__dict__)

単純にinsert

from polls.models import Question
from django.utils import timezone
# Questionにデータ設定
q1 = Question(question_text='質問1', pub_date=timezone.now())
q1.save()
q2 = Question(question_text='質問2', pub_date=timezone.now())
q2.save()
q3 = Question(question_text='質問3', pub_date=timezone.now())
q3.save()
# Questionの内容確認
for q in Question.objects.all():
   print(q)
{'_state': <django.db.models.base.ModelState object at 0x7ff7e06389a0>, 'id': 1, 'question_text': '質問1', 'pub_date': datetime.datetime(2020, 12, 1, 5, 46, 54, 680000, tzinfo=<UTC>)}
{'_state': <django.db.models.base.ModelState object at 0x7ff7e0638ee0>, 'id': 2, 'question_text': '質問2', 'pub_date': datetime.datetime(2020, 12, 1, 5, 46, 54, 725000, tzinfo=<UTC>)}
{'_state': <django.db.models.base.ModelState object at 0x7ff7e0638ca0>, 'id': 3, 'question_text': '質問3', 'pub_date': datetime.datetime(2020, 12, 1, 5, 46, 54, 734000, tzinfo=<UTC>)} 

外部キーを張ったテーブルにinsert

from polls.models import Choice, Question

# Question取得
q = Question.objects.get(id=1)
print(f'Question id=1 : {q}')
# Choiceデータ設定
q.choice_set.create(choice_text='選択肢1', votes=0)
q.choice_set.create(choice_text='選択肢2', votes=1)
q.choice_set.create(choice_text='選択肢3', votes=2)
# 確認
for c in q.choice_set.all():
    print(c)
Question id=1 : {'_state': <django.db.models.base.ModelState object at 0x7f80fefec2e0>, 'id': 1, 'question_text': '質問1', 'pub_date': datetime.datetime(2020, 12, 1, 5, 46, 54, 680000, tzinfo=<UTC>)}
{'_state': <django.db.models.base.ModelState object at 0x7f80ff008e80>, 'id': 1, 'question_id': 1, 'choice_text': '選択肢1', 'votes': 0}
{'_state': <django.db.models.base.ModelState object at 0x7f80ff008f10>, 'id': 2, 'question_id': 1, 'choice_text': '選択肢2', 'votes': 1}
{'_state': <django.db.models.base.ModelState object at 0x7f80ff008d00>, 'id': 3, 'question_id': 1, 'choice_text': '選択肢3', 'votes': 2}

MongoDBでデータの内容を確認

mongo
> use poll
> db.polls_question.find()
{ "_id" : ObjectId("5fc5d8ce6626f3a8c904db3c"), "id" : 1, "question_text" : "質問1", "pub_date" : ISODate("2020-12-01T05:46:54.680Z") }
{ "_id" : ObjectId("5fc5d8ce6626f3a8c904db3d"), "id" : 2, "question_text" : "質問2", "pub_date" : ISODate("2020-12-01T05:46:54.725Z") }
{ "_id" : ObjectId("5fc5d8ce6626f3a8c904db3e"), "id" : 3, "question_text" : "質問3", "pub_date" : ISODate("2020-12-01T05:46:54.734Z") }
> db.polls_choice.find()
{ "_id" : ObjectId("5fc5dd5759846395af0570be"), "id" : 1, "question_id" : 1, "choice_text" : "選択肢1", "votes" : 0 }
{ "_id" : ObjectId("5fc5dd5759846395af0570bf"), "id" : 2, "question_id" : 1, "choice_text" : "選択肢2", "votes" : 1 }
{ "_id" : ObjectId("5fc5dd5759846395af0570c0"), "id" : 3, "question_id" : 1, "choice_text" : "選択肢3", "votes" : 2 }

参考

コメントを残す

メールアドレスが公開されることはありません。