Djangoの自動主キーフィールド

Djangoではモデルクラスに primary_key=True のフィールドを明示的に定義しない場合、自動で id という名前で主キーのフィールドが追加されます。

このとき使われるフィールドのクラスは、Django 3.1以前では AutoField でしたが、Django 3.2から settings.DEFAULT_AUTO_FIELD で指定されたクラスが使われるようになりました。

Djangoにビルトインされている自動インクリメントされる主キーのフィールドクラスは次のとおりです。

  • AutoField
    • 範囲: 1 ~ 2147483647
    • IntegerFieldを継承している
  • BigAutoField
    • Django 1.10 で追加
    • 範囲: 1 ~ 9223372036854775807
    • BigIntegerFieldを継承している
  • SmallAutoField
    • Django 3.0 で追加
    • 範囲: 1 ~ 32767
    • SmallIntegerFieldを継承している

settings.DEFAULT_AUTO_FIELD について

settings.DEFAULT_AUTO_FIELD は、Django 3.2で追加されました。 settings.pyに定義がない場合のデフォルト値は 'django.db.fields.AutoField' です。 startprojectで新規にプロジェクトを作成した場合は、settings.pyには DEFAULT_AUTO_FIELD = 'django.db.fields.BigAutoField' が記述されます。

AutoFieldからBigAutoFieldへのマイグレーション

自動で追加されているidフィールドを、AutoFieldからBigAutoFieldに変更したい場合、settings.py に DEFAULT_AUTO_FIELD = 'django.db.fields.BigAutoField' を記述してからmakemigrationsを実行すると、スキーマ変更のマイグレーションファイルが作られます。

あとはいつも通りマイグレーションを実施できます。

参考

Ubuntu 20.04(Focal Fossa)にdeadsnakes PPAでPython3.9をインストールする

Ubuntu向けのPPAであるdeadsnakesを使うと、aptコマンドで複数のPythonバージョンを簡単にインストールできます。

add-apt-repositoryコマンドをインストール

PPAのaptリポジトリの追加に add-apt-repository コマンドを使います。 software-properties-common パッケージに含まれています。

sudo apt install -y software-properties-common

deadsnakes PPAのリポジトリを有効化

aptコマンドでインストールするために、deadsnakes PPAのリポジトリを有効化します。

sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt update

成功すれば apt search python3.9 コマンドのようにしてパッケージを探すと、列挙されるようになります。

Python 3.9をインストール

スタンダードに venv を使える環境を作ります。

sudo apt install -y python3.9 python3.9-dev python3.9-venv

成功すれば python3.9 -V コマンドでPython 3.9のバージョンが表示されるようになります。

ensurepip

venvのみで運用する場合、venvを作ったときにvenv環境にはpipコマンドが入るので、これは必須ではありませんが、venvなしでもpipコマンドを使いたい場合にはensurepipを実行しておくとよいです。

python3.9 -m ensurepip --default-pip --user

~/.local/bin ディレクトリに pip コマンドが追加されます。PATHを通しておくとよいかと思います。

書籍紹介:エキスパートPythonプログラミング改訂3版

『エキスパートPythonプログラミング 改訂3版』を査読でお手伝いしまして、本書をいただきましたので紹介します。

最初に手にとった際、「分厚い・・・」と感じました。手元に初版から改訂3版までがあるのですが、ページ数はそれぞれ次の通りです。

  • 初版:416ページ
  • 改訂2版:520ページ
  • 改訂3版:616ページ

これまで改訂のたびに100ページほど増えてました。

改訂3版はPython3.9をターゲットにしています。

改訂2版の際はPython2系と3系の比較の話などがありましたが、Python2系は完全にEOLとなり、Python3系のほうが一般的な状況となったので、2系の話は基本的にありません。

また、3系でもEOLとなったバージョンの話は削除され、比較的最近入った機能などの説明が追加されています。

「古くなったものが削除され、新しいものが追加された」という感じの改訂になっています。

レベル感は以前と変わらず、中級、上級者向けの内容となっています。

書籍紹介:実践Django Pythonによる本格Webアプリケーション開発

@c_bata_ さんの著書、『実践Django Pythonによる本格Webアプリケーション開発』をいただいたので紹介します。

本書の内容

Djangoの基本機能、モデルとクエリ操作、ビュー、テンプレート、フォーム、テスト、認証と認可、Django Rest FrameworkによるAPI開発を実際に動作するコードとともに説明をしています。

特に以下の点はおもしろいと思いました。

  • テストコードを多く記述している
    • テストコードを始めに書いて、テストをFailにしたあとで、テストコードがSuccessになるよう実装を進めている
  • セキュリティの説明で、実際に問題発生するコードを説明してから、解決方法の説明をしている
  • クエリ数を削減するパフォーマンスチューニングの話がある
    • SQLの実行計画の確認やインデックスについての説明がある

また、題材となっている「コードスニペット共有サイト」のアプリ開発で、サードパーティライブラリをうまく活用している点もよかったです。

Djangoのバージョンは、現時点では最新版となる 3.2系 に対応しているため、これからDjangoを使う人にとってもよいと思います。

対象読者

対象読者は本書の最初に書かれています。

  • Pythonの基本が理解できている
  • 簡単なWebアプリケーションの開発経験がある(言語やフレームワークは問わない)

Pythonの文法や使い方の説明は無いので、Pythonについては別途学習が必要です。

Webアプリケーションの基本的な仕組み(HTTPやHTML、CSS、通信の仕組みなど)の説明は省略されているので、別途学習するとよいと思います。

SQLの文法やデータベースの使い方の説明は省略されているので、別途学習するとよいと思います。

プログラミング初心者の方にはおすすめできません(想定してないと思います)

Djangoを使って簡単なアプリを書いたことはあるけど、この次に何をしたらよいのかわからない」という人にはオススメです。

Django初級~中級ぐらいのレベル感だと思います。

その他

  • 査読協力に載ってる方は見知った人たち
    • aodagがDjangoの本を査読しているぞ!

Djangoフレームワークのセッションの有効期限

Djangoフレームワークのセッションの有効期限について調べる必要があったのでまとめておく。

試したバージョンは、Python 3.9、Django 3.2.4。

ドキュメント

セッションのデフォルト設定

Djangoでプロジェクト生成した際のデフォルトの settings.py では、セッションのアプリケーションは有効になっている。

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',  # セッションアプリケーション
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',  # セッションミドルウェア
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

その他にセッションの設定は記載されていないので、デフォルトの設定が使われる。

デフォルトの設定値は、ドキュメントに記載がある。

https://docs.djangoproject.com/ja/3.2/ref/settings/#sessions

設定値の実装を確認したい場合は django.conf.global_settings のコードを読む。

https://github.com/django/django/blob/main/django/conf/global_settings.py

有効期限の扱い

Djangoのセッションは 「最後に更新されたときから有効期限の設定の期間」 が有効期限となる。

既存のセッションのデータがViewなどでの処理で更新された場合、 「有効期限が自動的に延長されていく」 といった仕様になる。

デフォルトの設定では、セッションのデータを参照するだけではセッションは更新されないので、 「最後にアクセスがあったときから~」ではない ことに注意する。

セッションの有効期限を延長する

Djangoのセッションの有効期限を延長したい場合は、セッションの更新を行う。

方法はいくつかある。

  • セッションの値を変更する
    • セッションの値を変更すると、バックエンドでデータが保存、更新されるため、有効期限が延長される
  • セッションの値は変更しないが明示的に更新する
    • request.session.modified = True のようにViewの中で記述しておくと、セッションミドルウェアで変更扱いとして保存、更新される
  • すべてのリクエストでセッションを保存する
    • settings.pyの SESSION_SAVE_EVERY_REQUESTTrue を指定すると、セッションが発行されている場合には、ミドルウェアによりすべてのリクエストでセッションが保存、更新される
    • この方法だと、 「リクエスト毎にセッションの有効期限が延長される」 というのを実現可能
    • SESSION_SAVE_EVERY_REQUEST = True の場合、セッションの保存先のストレージに書き込み処理が多数発生するので、負荷が問題にならないか気をつける必要がある。
class MyView(View):
    def get(self, request):
        ...
        # Viewでセッションの保存を行う場合はどちらかの方法でよい
        request.session["foo"] = "bar"  # セッションの値を更新する例

        request.session.modified = True   # 明示的にセッション保存を指定する例, セッションの値を更新した場合は不要
        ...

セッションが保存されるタイミングはドキュメントにも記載があるので、参考に。

https://docs.djangoproject.com/ja/3.2/topics/http/sessions/#when-sessions-are-saved

セカンドハウスのある生活をしてみた所感

これは pyspa Advent Calendar 2020 の2日目の記事です。

https://adventar.org/calendars/5310

去年の秋から、生活する場所を東京と千葉の2ヶ所にしています。このことについての所感です。

きっかけ

東京の23区外でマンションの部屋を所有して住んでいましたが、プライベートで千葉市に行くことが増えたので、移動が大変だなと思ったのがはじまりです。

東京の家を引き払って引っ越すか考えたのですが、持ち家で色々と便利だったので、東京の持ち家を維持しつつ、千葉のほうは賃貸物件に住むことにしました。

元々、東京の家のローン返済が終わったあと、田舎の方に別荘があっても良いなとは思っていて、「セカンドハウスを持つ感覚とはどういうものか」を経験しておきたかったのもあり、決意しました。

家のエリア、スペック

持ち家のほうは東京の東久留米市です。駅からも距離があり、少し歩く場所ですが、全国チェーンの郊外店舗が多く、買い物には不便しない場所です。去年までは市民農園の畑を借りて野菜を作ったりもしました。畑と住宅街、チェーン系の店舗で構成される典型的な郊外エリアです。

もう一方のセカンドハウスは千葉市です。駅から徒歩10分以内ぐらいで、歓楽街も近く便利なエリアですが、スーパーマーケットは東久留米より少なくて、自炊の機会が多い自分としては、少し遠くても品揃えのよいスーパーマーケットまで足を伸ばしがちになってます。

  • 東久留米市
    • 持ち家、分譲マンション
    • 60平米ぐらい
    • 駅から徒歩20分ぐらい
    • 築10年以内
    • 一軒家や低層マンションが多いエリア
    • 買い物はスーパーマーケット、ホームセンターなどの郊外型店舗が徒歩、自転車圏内に多数あり
    • 飲食店は郊外型のチェーン系店舗が多くある、個人経営の店は少なめ
  • 千葉市
    • 賃貸マンション
    • 40平米ぐらい
    • 駅から徒歩5~10分ぐらい
    • 新築
    • 商業ビルが多いエリア
    • 買い物は駅ビルか、すこし駅から離れる方向の郊外型店舗
    • 飲食店は多い

過ごし方

どちらの家にも半々ぐらい滞在、ということはなく、月ごとに偏りがある感じで使ってます。

池袋、新宿、渋谷など山手線の西側で用事があるときは東京の家に帰ったり、また東京の家から行ったりしてます。

逆に山手線の東側の場合は千葉からのほうが鉄道でのアクセスが良いので、そちらを使ってます。

バイクや車で関東の西側に行くときは、東京の家からのほうが楽なので、東京の家を起点にしてます。

千葉の南部や茨城方面に行くときは、千葉からのほうが楽なので、千葉の家を起点にしてます。

仕事はリモートワークでできるので、家で過ごす時間も長く、気分で場所も変えられるのは良かったなと思いました。

毎日出勤が必要になると、どちらかの家の使用頻度は極端に少なくなるかもしれません。

自炊をする場合、日持ちしない食材を滞在しないほうの家に置けないので、冷凍食材や缶詰など日持ちする食材をストックしてうまく使うようにしています。

東京の家のほうが広いので、ホームパーティをする場合は東京のほうを使っています。

拠点間移動

拠点間の移動は所有してるオートバイ(中型400cc)か、鉄道です。

天気のよい日はオートバイで一般道路か高速道路を使って移動することが多いです。

以下のようにメリット・デメリットどちらもあり、場合によって使い分けています。

  • オートバイ
    • 所要時間は日中だと150分ぐらい、夜中だと80分ぐらい
    • 鉄道に比べて時間の制約が少ない(夜中でも移動できる)
    • 高速道路を使わなければ、電車賃より安く済む
    • 高速道路を使うと移動時間の短縮が大きい
    • 荷物をいくらか積載可能
    • 運転は楽しいけど、運転しないといけないので、移動中に他のことができない
    • 悪天候の場合はつらい
  • 鉄道+バス(徒歩)
    • 所要時間は150~180分ぐらい
    • 時間はかかるけど、移動中に作業したりできる
    • 移動途中に寄り道しやすい
      • バイクだと駐車場を探す必要があるので都心は若干面倒なのです
    • 悪天候でも移動が楽
    • 混雑時間帯だと疲れる
    • 感染症のリスクはバイク移動に比べたら高い

車を持つのが一番良さそうなんですが、維持費がバイクよりも高くなるので、まだ検討中です。

kane

2つの家を維持するので、費用はかかります。両方の家に生活するための家具、家電など一式も必要になります。

個人的にはどちらの家も家賃が高額だと思うエリアは外しています。

現状は住居にかかる費用は収入の2~3割程度におさまっているので、単純に維持するだけであればそこまで負担はないかな、という感じです。

持ち家のほうは住宅ローンが完済済みで、管理積立金と固定資産税の状態であるのが大きいです。

  • 光熱費は両方の家の基本使用料はかかるけど、プランによっては安くできる
  • 駐車場を借りる場合、両方の家で駐車場が欲しくなるので結構かかる
  • 移動にもお金がかかる

まあ、お金はかかりますね。

手入れ

家は使っていると汚れるし、掃除が必要になります。それぞれの家の使用頻度は減りますが、掃除する面積が増えるのでそこそこ大変です。

設備は経年劣化もあるので、なるべく長く使うためにも手入れをしたほうがよいです。

掃除や家の手入れを抵抗なくやれる人でないと、維持がつらくなるかもしれません。私は掃除は嫌いではないですが、時間がかかるので、短縮のために模索しているところです。

面倒な場合はお金で解決する方法もあります。ルンバなどのロボット掃除機も使っていくと良さそう。

その他、言いたいこととか

  • 郵便や荷物の受け取り
    • 基本的にどちらの家にも宅配ボックスがあるので、不在でも受け取れるようにはしています。
    • 対面での受け取りが必須のもの(冷蔵品や本人確認)は不在が数日続いて受け取り失敗することがしばしばあり、不便に感じました。
    • また運送会社の荷物の受け取りサービスは、自宅の住所が1ヶ所しか登録できないものがあり、不便に感じました。

やってみるまではどうなるか予想できなかったことも多かったのですが、セカンドハウスを持つのは中々良い体験だと思いました。

少なくとも活用できるうちは維持しようかなと思ってます。

次は小さい畑をやれる土地もほしいなーとぼんやり考えてます。

とにかく家は維持するにはそれなりにお金や労力が必要になります。

この記事がセカンドハウスを検討してる方の参考になれば幸いです。

Djangoの管理コマンドを上書き(置換え)する

Djangoフレームワークの管理コマンド(manage.py スクリプトのコマンド)をオーバーライド(上書き、置換え)する方法について。

管理コマンドの登録の仕組み

Djangoのドキュメントには、管理コマンドのオーバーライドについての記載があります。

https://docs.djangoproject.com/en/3.1/howto/custom-management-commands/#overriding-commands

Djangoのコマンドの登録メカニズムは、次の通りです。

  • 最初に組込みのコマンドがセットアップされます
  • INSTALLED_APPS のアプリケーションにコマンドがあれば登録します
    • コマンドはアプリケーションのディレクトリ以下に management.commands 以下のモジュールがロードされ、モジュール内のCommandクラスのインスタンスがコマンドとして登録されます
    • モジュール名がコマンド名として使われます(たとえば、 runserver コマンドなら runserver.py)
    • このとき、同じ名前のコマンドがあれば、アプリのコマンドで先に登録されたコマンドを上書き(オーバーライド)します
  • runserver コマンドについては、Django内部で、 django.contrib.staticfiles が組込みの runserver コマンドをオーバーライドしているので気をつける必要があります

既存のコマンドを置き換えてみる

myapp という名前のアプリケーションで、組込みのコマンド migrate を置き換えてみます。

試したバージョンは、 Python 3.8、 Django 3.1.3 です。

myappのディレクトリ構造は以下の通り:

myapp
├── __init__.py
├── admin.py
├── apps.py
├── management
│     ├── __init__.py
│     └── commands
│         ├── __init__.py
│         └── migrate.py
├── migrations
│     └── __init__.py
├── models.py
├── tests.py
└── views.py

myapp.py:

from django.core.management.base import BaseCommand


class Command(BaseCommand):
    def handle(self, *args, **kwargs):
        print("これはmyappのコマンドです")

組込みのコマンドを置き換える場合、組込みのコマンドを継承する必要は必須ではないです。例のように Command という名前のクラスで、 BaseCommand と同等の振る舞いができれば、コマンドとして利用できます。

実行結果

myappsettings.pyINSTALLED_APPS に登録されていると、組込みの migrate コマンドが myapp アプリのコマンドに置き換わります。

$ ./manage.py migrate
これはmyappのコマンドです