ひこぽんのーと

覚書と雑記です。

Djangoをやってみよう。 その7-管理サイト-

その6のつづき。

Apache TomcatにWebアプリケーションを登録する時、
管理画面を使ってデプロイすることができる。
これと似たようなもので、Djangoにも管理画面がある。
管理画面を使うには管理者ユーザを作成する必要がある。

と、その前に以下のコマンドを実行して管理画面等、基本機能を使用可能状態にする。
管理テーブルなんかが作られるため、プロジェクト作成後にやってしまえばよかった。

 python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, warship
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... 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 sessions.0001_initial... OK

管理テーブルができたら、管理ユーザ作成コマンドを実行する。
初回はコマンドでユーザを作るが、
以降は管理画面から追加できる。

python manage.py createsuperuser
Username (leave blank to use 'nagamitsu'): 
Email address: nagamitsu@foo.bar.com
Password: 
Password (again): 
Superuser created successfully.

ユーザを作成したら、サーバを起動して管理画面を起動してみる。

python manage.py runserver

管理画面のURLはこれだ。
http://127.0.0.1:8000/admin
f:id:nagamitsu1976:20170623144059p:plain
先ほど作ったユーザでログインしてみる。
f:id:nagamitsu1976:20170623144349p:plain
ログイン後、管理メニューのようなものが表示される。

Usersなどをクリックしてみるとわかると思うが、
今のところ、管理ユーザの追加・編集程度しかできないが、
定義を加えることで、
作成したアプリのモデルを管理画面から編集することができるようになる。

といったところで、次回へ続く。

Djangoをやってみよう。 その6-Model/DBの操作-

その5の続き。

まだ画面も何もないので、
コンソールからモデルの操作をやってみる。
実行自体は簡単でpythonの対話モードを使う。
ただし、Djangoの機能だったり、
helloサイト上のクラスを正しく使うには、
ちょっとした手順がある。

python manage.py shell

このコマンドを実行するとhelloサイトの設定が読み込まれた状態で
Pythonの対話モードが起動する。

対話モードに入ったらまず、艦種を登録してみる。

>>> from warship.models import ShipClass
>>> ship_class = ShipClass()
>>> ship_class.name = u'駆逐艦'
>>> ship_class.save()

ShipClassをインポートしたあと、ShipClassのインスタンスを作り、
nameに「駆逐艦」を設定したあと、saveメソッドを呼ぶだけ。
これで、DBに対してInsertが走る。

登録されたかどうか、検索してみる。
とりあえず、全件検索の<モデル>.objects.all()を実行してみる。

>>> ShipClass.objects.all()
<QuerySet [<ShipClass: ShipClass object>]>

なんか帰ってきたがよくわからんね。
チュートリアルでは「モデルに__str__メソッドを追加するのが重要です。」なんて、
あとに書いてある。
こっちも真似してmodels.pyのクラスを以下のように変えてみる。

from django.db import models

# Create your models here.


class ShipClass(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name

class Warship(models.Model):
    ship_class = models.ForeignKey(ShipClass, on_delete=models.CASCADE)
    name = models.CharField(max_length=30)

    def __str__(self):
        return u"{0} - {1}".format(self.ship_class, self.name)

そしたら、一旦、対話モードを終了し、再度、対話モードで実行しなおして
検索を行ってみる。

>>> ShipClass.objects.all()
<QuerySet [<ShipClass: 駆逐艦>]>

中身が見えるようになったので、登録されていたことが確認できた。
all()は全件検索なので、絞り込みをやってみよう。

>>> ship_class = ShipClass.objects.filter(name=u"駆逐艦")
>>> print(ship_class)
<QuerySet [<ShipClass: 駆逐艦>]>

絞り込みはfilter()。
抽出条件をキーワード引数で指定すると、絞り込みを行ってくれる。

ついでに、もう一回登録をやってみる。
今度は、艦船を登録してみる。

>>> ship_class = ShipClass.objects.filter(name=u"駆逐艦")[0]
>>> from warship.models import Warship
>>> warship = Warship()
>>> warship.ship_class = ship_class
>>> warship.name = u"暁"
>>> warship.save()
>>> Warship.objects.all()
<QuerySet [<Warship: 駆逐艦 - 暁>]>

とまぁ、うまくできているようだ。
データベースを触らずにテーブル作って、データ登録までできるって
なんて楽なんだろう。

といったところで、次回へ続く。

Djangoをやってみよう。 その5-Modelの追加-

その4のつづき。

前回追加した、warshipアプリにモデルを追加して
データベースを触ってみようと思う。

Modelの作成

warship/models.pyを開いて、ここにクラスの定義を記述する。

from django.db import models

# Create your models here.


class ShipClass(models.Model):
    name = models.CharField(max_length=30)


class Warship(models.Model):
    ship_class = models.ForeignKey(ShipClass, on_delete=models.CASCADE)
    name = models.CharField(max_length=30)

サンプルでは艦種クラスと艦船クラスを作成した。
艦種は「駆逐艦」とか「戦艦」とかそんな種別を表し、艦船は種別と名前を持つ、そんなイメージ。
ここでのモデルは当然、DBから取得した値を格納するためのものであるので、
クラスのメンバもDBに関するものを定義することになる。
ここで登場したものでは、models.CharFieldクラスとForeignKeyクラスがある。
CharFieldはいわゆる、Varchar型、Char型なんかを格納するためのクラス。
ForeignKeyはそのまま、外部キーによる結合を想定している場合に使用するクラスとなっている。
引数に結合するクラスと、削除時にカスケードするかなどの定義を設定できる。
これら以外にも、整数型のためのIntegerFieldクラスだとか、BooleanFieldクラスなんかも当然あるが、
今回は割愛する。

モデルを定義したら、テーブルを作成する。
Djangoはモデルに応じて自動的にテーブルを作ってくれるので楽ちんである。
そのためのコマンドを実行する。

python manage.py makemigrations warship

実行するとアプリケーション内のモデルの変更点を認識し、
適切なコマンドを作ってくれる。

Migrations for 'warship':
  warship/migrations/0001_initial.py:
    - Create model ShipClass
    - Create model Warship

今回は初めてのモデル作成だったのでCreate Tableのコマンドが作られたようだ。
どんなSQLになるかについては、またまたコマンドで確認できる。

python manage.py sqlmigrate warship 0001
BEGIN;
--
-- Create model ShipClass
--
CREATE TABLE "warship_shipclass" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL);
--
-- Create model Warship
--
CREATE TABLE "warship_warship" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL, "ship_class_id" integer NOT NULL REFERENCES "warship_shipclass" ("id"));
CREATE INDEX "warship_warship_ab7d680f" ON "warship_warship" ("ship_class_id");
COMMIT;

とまぁ、こんなSQLが実行されるらしい。
中身がわかったところで、テーブル作成を行ってみる。
DBを直接触る必要がなく、Djangoのコマンドで行える。

python manage.py migrate warship 0001

実行後、こんなメッセージがでれば成功。

Operations to perform:
  Target specific migration: 0001_initial, from warship
Running migrations:
  Applying warship.0001_initial... OK

これでモデルとDBができた。
データ登録、検索ができるか、などについては、次回に続く。

Djangoをやってみよう。 その4-アプリケーションの追加-

その3のつづき。

前回、DB設定を行ったので、
検証も兼ねてDB接続する機能を触ってみたいと思う。

というわけで、おもむろにhelloサイトにアプリケーションを追加しようと思う。
アプリケーションの追加にはコマンドを使う。
ここでは追加するアプリケーションを'warship'とした。
コマンドを実行する場合は、プロジェクトディレクトに移動してから行う。

python manage.py startapp warship

コマンドが終了するとhelloプロジェクトにwarshipが追加される。

hello
├── db.sqlite3
├── hello
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── warship
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

warshipディレクトリが追加されているものの、
このままではhelloサイトにはwarshipアプリが追加されたことはわからない。
そこで、settings.pyに設定を追加してwarshipアプリが追加されたことを教えてやる必要がある。

# Application definition

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

setting.pyのINSTALLED_APPSに追加したアプリのconfigクラスを追加してやればいい。
この場合では、warship/apps.pyにWarshipConfigクラスが定義されている。
定義を加えることによって、
helloサイトは自身にwarshipアプリがいることを認識できるようになる。


といったところで、次回につづく。

Djangoをやってみよう。 その3-データベース設定-

その2のつづき。

DjangoにはO/Rマッパーの機能が標準で付いているので、
こちらの設定もあわせて行う。
データベースは、主にOracle, PostgreSQL, MySQL, SQLiteから選べる。

DB設定

前回作ったhelloプロジェクトの配下にhelloサイトのディレクトリがあり、
その配下にサイト全体の設定を記述するsettig.pyがある。
DB接続設定もここに記述することになる。

hello
├── hello
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py

ちなみにこれから作ろうとするアプリは、
helloサイト上のアプリケーションとして作ることになる。

ともあれ、初期値で同じ記述がすでにされているとは思うが、
SQLiteを使った場合の設定を以下に書いておく。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

認証用DB, ユーザデータ用DBなど複数のDB定義を記述することで
複数のDBをプログラムから選択して使用することもできる。
その際にはDatabase Routerクラスを実装するなど、
それようの処理なり定義を記述する必要がある。

つづく。

pythonで音声を再生するのこと その4

おまけ。

pysdl2のsdl2.sdlmixer.Mix_LoadMUSを使った場合、
一度に鳴らせる音声はひとつだけ。

つまり、BGMを背景にセリフを再生する、といった事は、
この関数ではできない。

そんな場合は、チャネル再生を使う。
チャネル再生には、チャンクとチャネルを取得すればよく、
関数も用意されている。

パッケージ 関数 備考
sdl2.sdlmixer Mix_LoadWAV 音声を読み込み、チャンクを取得する。
WAVE, AIFF, RIFF, OGG, VOCが利用可能。
sdl2.sdlmixer Mix_PlayChannel チャネルを取得して再生を行う。
sdl2.sdlmixer Mix_Pause 再生の停止
sdl2.sdlmixer Mix_FreeChunk チャンクの開放

以下にソース。

# -*- coding: utf-8 -*-

from ctypes import *
from sdl2 import *
from sdl2.sdlmixer import *
from time import sleep


if __name__ == u"__main__":
	SDL_Init(SDL_INIT_AUDIO)
	Mix_Init(MIX_INIT_OGG)
	Mix_OpenAudio(22050, AUDIO_S16, 2, 4096)

	path = c_char_p(b"OGGファイルのパス")
	chunk = Mix_LoadWAV(path)
	Mix_VolumeMusic(64)
	channel = Mix_PlayChannel(-1, chunk, 1)
	sleep(100)
	Mix_Pause(channel)
	Mix_FreeChunk(chunk)
	SDL_Quit()

前回のソースと今回のソースを組み合わせれば、
複数の音声を同時に再生できるようになる。
チャネル再生にはMP3が使えないっと言うのが玉にキズだけど。。。

pythonで音声を再生するのこと その3

その2の続き。

再生の手順としては、基本的にpygameの時とは変わらない。

ライブラリの初期化 → 音声のロード → 再生・停止 → ライブラリの開放

といった手順はわかるものの、どう書くのか。
pythonのサンプルも見つけられなかったので、
sdl-mixerのサイトからダウンロードできるC用のサンプルを参考に作ってみた。

一応、使う関数は以下の通り。

パッケージ 関数 備考
sdl2 SDL_Init ライブラリの初期化。
引数に初期化対象を指定する必要がある。
pygame.init()に当たる。
sdl2 SDL_Quit ライブラリの開放。
sdl2.sdlmixer Mix_Init ミキサーの初期化。再生対象のファイル形式を指定する。
pygame.mixer.init()にあたる。
sdl2.sdlmixer Mix_OpenAudio ミキサーの再生クオリティを指定する。
pygame.mixer.init()にあたる。
sdl2.sdlmixer Mix_LoadMUS 音声ファイルの読み込み。
pygame.mixer.music.load()にあたる。
sdl2.sdlmixer Mix_PlayMusic 音声ファイルの再生。
pygame.mixer.music.play()にあたる。
sdl2.sdlmixer Mix_PauseMusic 再生の停止。
pygame.mixer.music.pause()にあたる。
sdl2.sdlmixer Mix_FreeMusic 音声ファイルの開放。

以下にソース。

# -*- coding: utf-8 -*-

from ctypes import *
from sdl2 import *
from sdl2.sdlmixer import *
from time import sleep


if __name__ == u"__main__":
	SDL_Init(SDL_INIT_AUDIO)
	Mix_Init(MIX_INIT_MP3)
	Mix_OpenAudio(22050, AUDIO_S16, 2, 4096)

	path = c_char_p(b"MP3のファイルパス")
	music = Mix_LoadMUS(path)
	Mix_VolumeMusic(64)
	Mix_PlayMusic(music, 1)
	sleep(300)
	Mix_PauseMusic()
	Mix_FreeMusic(music)
	SDL_Quit()

とまぁ、簡単に音が出る、けれど、注意点もある。

関数呼び出しのパラメータと復帰値については注意が必要。
基本、こいつらはCの型を要求する。
pythonの型からCの型へ変えてやらないと、うまく実行できない。*1
Mix_LoadMUSの引数は、libsdl-mixerでは、char *なので、
ここではctypesを使って、byte列をCのchar *に変えて渡している。
また、ここではチェックを省いているが、
復帰値は関数実行の成否を表しているので、都度、チェックを行い、
エラー時には中断するなりのエラーハンドリングを書いてやる必要がある。

それさえ気をつければ、pygameのように扱える、と思う。

*1:正確にはpysdl2がそういうスタンスだからだが。。。