django、DBシーケンスを作成、使用する


django の model に AutoField ってわけではなく、 別途シーケンスオブジェクトから、採番した番号とあるカラムに設定したくて、
調べた結果を記載します。

前提

環境情報は以下の通りです。

  • OS
sw_vers
----------------------------
ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G1108
----------------------------
  • python version
python3 -V
----------------------------
Python 3.5.1
----------------------------
  • Django Version
pip list
----------------------------
Django (1.10)
----------------------------
  • DB
psql -V   
----------------------------
psql (PostgreSQL) 9.5.2
----------------------------

自前でシーケンスオブジェクトを作成し、シーケンス取得クエリを発行する

Django 1.7 で、マイグレーションファイルでフルテキストインデックスを作成する | ytyng.com と、
sql - Trying to get the next value in sequence from a postgres DB, with django - Stack Overflow と、
Django, accessing PostgreSQL sequence - Stack Overflow
見る限り、

  • Migration を書いて create sequence を作成する。

  • select nextval でシーケンスを採番する。

方式で、できそうです。

Migration を書いて create sequence を作成する。

  • 空のマイグレーションファイルを作成する
./manage.py makemigrations festivals4partypeople --empty

------------------------------------------
Migrations for 'festivals4partypeople':
  festivals4partypeople/migrations/0046_auto_20161125_0145.py:

------------------------------------------
  • マイグレーションファイルに migrations.RunSQL で create sequence 文 を書く

0046_auto_20161125_0145.py を 修正して、
create sequence を 追加しました。

# -*- coding: utf-8 -*-
# Generated by Django 1.10.2 on 2016-11-24 16:45
from __future__ import unicode_literals

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ('festivals4partypeople', '0045_auto_20161124_2238'),
    ]

    operations = [
        "CREATE SEQUENCE festival_classification_seq ",
    ]
  • migrate 実行
 ./manage.py migrate

-----------------------------------
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, festivals4partypeople, sessions
Running migrations:
  Applying festivals4partypeople.0046_auto_20161125_0145... OK
-----------------------------------
  • シーケンス取得メソッド作成
    @staticmethod
    def __create_festival_classification_seq():

        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("select nextval('festival_classification_seq')")
        result = cursor.fetchone()
        return result[0]

という形で、シーケンスは発行できました。


django-sequences を使ってシーケンスを発行する

aaugustin/django-sequences: Generate gap-less sequences of integer values.
というシーケンス発行ライブラリがあるので、そちらについて記載します。
dbシーケンスを使うのではなく、
simple な シーケンス発行Tableを使って連番を作るライブラリのようです。

インストール

django-sequences/README.rst at master · aaugustin/django-sequences
に従って、インストールします。

pip install django-sequences
-------------------------------------------
Collecting django-sequences
  Downloading django_sequences-1.0.1-py2.py3-none-any.whl
Installing collected packages: django-sequences
Successfully installed django-sequences-1.0.1
-------------------------------------------

settings.py に django-sequences を追加する

INSTALLED_APPS += ['sequences.apps.SequencesConfig']

migrate 実行

python3 manage.py migrate
------------------------------------------
TypeError: can only concatenate tuple (not "list") to tuple
------------------------------------------

INSTALLED_APPS が tuple だったらしいので以下の通り修正

INSTALLED_APPS = (
    'festivals4partypeople',
    'festivals_crawler.apps.FestivalsCrawlerConfig',
    'django_extensions',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sequences.apps.SequencesConfig'
)

再度、migrate を実行

 python3 manage.py migrate
------------------------------------
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, festivals4partypeople, sequences, sessions
Running migrations:
  Applying sequences.0001_initial... OK
------------------------------------

シーケンス採番

以下のように書けます。

  • python 記述

        from sequences import get_next_value
        print(get_next_value('festival_classification_seq'))
    

  • output ※2回採番しています。

    2
    

採番テーブル

postgress では、以下のテーブルができていました。

  • SQL

    select * from sequences_sequence;
    

  • output

                name             | last 
    -----------------------------+------
     festival_classification_seq |    2
    (1 row)
    

どちらがいいのか

高負荷時はシーケンスとして作る方が、早いけど、
別に動くうちは、django-sequences の方が楽かなと。

今は、シーケンス自体それほど使わないので、
個人的には、自前でシーケンスオブジェクトを作成し、シーケンス取得クエリを発行する
方式でいこうかなと思います。

以上です。

コメント