akiyoko blog

akiyoko の IT技術系ブログです

Django モデルのフィールドの「auto_now_add」「auto_now」オプションの挙動を詳しく調べてみた

Django モデルに登録日時や更新日時のフィールドを付加する場合、「auto_now_add」オプションや「auto_now」オプションを利用すると便利です。それらのオプションの挙動について詳しく調べてみたので、まとめておきます。

f:id:akiyoko:20200521233958p:plain

TL;DR


挙動

たとえば、

shop/models.py

from django.db import models


class Book(models.Model):
    """本モデル"""

    class Meta:
        db_table = 'book'
        verbose_name = verbose_name_plural = '本'

    title = models.CharField('タイトル', max_length=255)
    price = models.PositiveIntegerField('価格', null=True, blank=True)
    created_at = models.DateTimeField('登録日時', auto_now_add=True)
    updated_at = models.DateTimeField('更新日時', auto_now=True)

    def __str__(self):
        return self.title

というフィールドがあるとすると、

登録時

  • 「auto_now_add=True」のフィールド(created_at)に現在日時が自動的にセットされる
  • 「auto_now=True」のフィールド(updated_at)に現在日時が自動的にセットされる

更新時

  • 「auto_now=True」のフィールド(updated_at)に現在日時が自動的にセットされる

という挙動になります。


つまり、テストを書くとこういうことになります(参考までに freezegununittest.mock を使ったものを併記)。


shop/tests/test_models.py

from datetime import datetime
from unittest.mock import patch

from django.test import TestCase
from django.utils import timezone
from freezegun import freeze_time

from ..models import Book


class TestBook(TestCase):

    @freeze_time('2020-01-01 01:01:01')
    def test_save_with_freezegun(self):
        book = Book(title='Django本', price=1500)
        # 登録
        book.save()

        # 登録日時・更新日時のどちらも値がセットされる
        self.assertEqual(book.created_at, datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))
        self.assertEqual(book.updated_at, datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))

        with(freeze_time('2020-02-02 02:02:02')):
            # 更新
            book.save()

        # 更新日時のみが更新される
        self.assertEqual(book.created_at, datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))
        self.assertEqual(book.updated_at, datetime(2020, 2, 2, 2, 2, 2, tzinfo=timezone.utc))

    @patch('django.utils.timezone.now',
           return_value=datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))
    def test_save_with_mock(self, _mock_now):
        book = Book(title='Django本', price=1500)
        # 登録
        book.save()

        # 登録日時・更新日時のどちらも値がセットされる
        self.assertEqual(book.created_at, datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))
        self.assertEqual(book.updated_at, datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))

        _mock_now.return_value = datetime(2020, 2, 2, 2, 2, 2, tzinfo=timezone.utc)
        # 更新
        book.save()

        # 更新日時のみが更新される
        self.assertEqual(book.created_at, datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc))
        self.assertEqual(book.updated_at, datetime(2020, 2, 2, 2, 2, 2, tzinfo=timezone.utc))



 
フィールドに現在日時が自動的にセットされる仕組みを見てみると、次のように、pre_save() で django.utils.timezone.now() が呼ばれています。

django.db.models.fields.DateTimeField.pre_save *1

    def pre_save(self, model_instance, add):
        if self.auto_now or (self.auto_now_add and add):
            value = timezone.now()
            setattr(model_instance, self.attname, value)
            return value
        else:
            return super().pre_save(model_instance, add)


そして django.utils.timezone.now() では、Django の設定ファイルの「USE_TZ」が True の場合は datetime.datetime.utcnow() が呼ばれています。

django.utils.timezone.now *2

def now():
    """
    Return an aware or naive datetime.datetime, depending on settings.USE_TZ.
    """
    if settings.USE_TZ:
        # timeit shows that datetime.now(tz=utc) is 24% slower
        return datetime.utcnow().replace(tzinfo=utc)
    else:
        return datetime.now()


freezegun の freezegun.api.FakeDatetime が次のように datetime.datetime.now() や utcnow() などをモックしてくれているので、「auto_now_add」や「auto_now」にも適用できるのですね。よかった。

freezegun.api.FakeDatetime *3

class FakeDatetime(with_metaclass(FakeDatetimeMeta, real_datetime, FakeDate)):

    ...(略)...

    @classmethod
    def now(cls, tz=None):
        now = cls._time_to_freeze() or real_datetime.now()
        if tz:
            result = tz.fromutc(now.replace(tzinfo=tz)) + cls._tz_offset()
        else:
            result = now + cls._tz_offset()
        return datetime_to_fakedatetime(result)

    ...(略)...

    @classmethod
    def utcnow(cls):
        result = cls._time_to_freeze() or real_datetime.utcnow()
        return datetime_to_fakedatetime(result)

    ...(略)...


 

「auto_now_add」や「auto_now」を使うことによる弊害

便利でよいのですが、二点ほど弊害があります。

1.任意の値で更新できない

実例を挙げると、

>>> from shop.models import Book
>>> from datetime import datetime
>>> from django.utils import timezone
>>> book = Book()
>>> book.updated_at = datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc)
>>> book.save()
>>> book.updated_at
datetime.datetime(2020, 5, 21, 6, 41, 7, 219328, tzinfo=<UTC>)

という感じで、保存時に現在日時で上書きされてしまいます。

(参考)www.ianlewis.org


しかしながら、登録日時や更新日時フィールドに「auto_now_add」および「auto_now」オプションを利用する場合、任意の値で更新したいユースケースとしてはユニットテストのときくらいでしょうから、実害はあまり無いと言えるかもしれません。
 

2.管理サイトの詳細画面で表示されない

「auto_now_add」もしくは「auto_now」オプションを利用すると、自動的に editable オプションが False になるので、管理サイトの詳細画面で表示されなくなります。

f:id:akiyoko:20200521232712p:plain

django.db.models.fields.DateField.__init__ *4

class DateField(DateTimeCheckMixin, Field):
    ...(略)...

    def __init__(self, verbose_name=None, name=None, auto_now=False,
                 auto_now_add=False, **kwargs):
        self.auto_now, self.auto_now_add = auto_now, auto_now_add
        if auto_now or auto_now_add:
            kwargs['editable'] = False
            kwargs['blank'] = True
        super().__init__(verbose_name, name, **kwargs)

    ...(略)...

class DateTimeField(DateField):
    ...(略)...

    # __init__ is inherited from DateField


詳細画面にフィールドを表示するだけであれば(任意の値で登録・更新できないが)、ModelAdmin の「fields」と「readonly_fields」に同時に列挙することで対応は可能です。

shop/admin.py

from django.contrib import admin

from .models import Book


class BookAdmin(admin.ModelAdmin):
    fields = ('title', 'price', 'created_at', 'updated_at')
    readonly_fields = ('created_at', 'updated_at')


admin.site.register(Book, BookAdmin)

f:id:akiyoko:20200521233140p:plain



これらの弊害については一応解決策がありますが、ちょっと面倒です。あまりオススメしません。

stackoverflow.com



 

宣伝

Django の本を3冊書きました。Django 開発のお供にどうぞ。

現場で使える Django の教科書《基礎編》

★ Amazon(電子版/ペーパー版)


★ BOOTH(ペーパー版)


現場で使える Django の教科書《実践編》

★ Amazon(電子版)


★ BOOTH(ペーパー版)


現場で使える Django REST Framework の教科書

★ Amazon(電子版)


★ BOOTH(ペーパー版)

PyCharm のオレオレ最強設定(2020.1 バージョン)

PyCharm 大好き akiyoko です。

以前、「PyCharm のオレオレ最強設定」という記事を書いたのですが、あれから3年経ち、PyCharm もどんどん新しいバージョンがリリースされる中で記事の内容が少し古くなっていたので、今回、最新バージョンの「PyCharm 2020.1」に合わせて記事を書き直してみました。


f:id:akiyoko:20200508040938p:plain


PyCharm を含めた JetBrains 社の IDE は「out of the box(箱から取り出してすぐに使える、難しい設定などは一切なしで使える)」というのが大きな魅力のひとつですが、今回紹介する環境設定をすることでさらなる実力を発揮させることができます。


なお、PyCharm には大きく分けて、無償版の「PyCharm CE(Community Edition)」と有償版の「PyCharm Professional」がありますが *1、「PyCharm CE」の設定は「PyCharm Professional」でもそのまま利用可能です。



目次


今回の設定については

  • バージョン:PyCharm CE 2020.1
  • OS:Windows 10 Home / macOS 10.15 Catalina

で動作確認しています(画面キャプチャは Windows 版のもの)。


なお、今回紹介するのはあくまで筆者の(オレオレ)最強設定ですので、異論・反論は緩やかな範囲でお願いします。


 

PyCharm CE のインストール手順

まずは PyCharm CE 2020.1 のインストール手順について軽く説明します。


PyCharm 公式ダウンロードページ から、「コミュニティ」(PyCharm CE)の方の「ダウンロード」ボタンをクリックして、インストーラをダウンロードします。

f:id:akiyoko:20200508034016p:plain


あとはインストーラをダブルクリックして、表示される内容に従ってインストールを実行してください。


f:id:akiyoko:20200501114537p:plain:w400


デフォルトでは、Windows の場合は

  • C:\Program Files\JetBrains\PyCharm Community Edition 2020.1

macOS の場合は

  • ~/Library/Application Support/JetBrains/PyCharmCE2020.1

にインストールされます。


 

環境設定

上部メニューの[File] > [Settings](macOS 版では[PyCharm] > [Preferences])から、PyCharm の環境設定が変更できます。

1.テーマ設定

[Appearance & Behavior] > [Appearance]

[Theme] をデフォルトの「IntelliJ Light」から、「Darcura」(少し暗めのテーマ)に変更します。あくまで任意で。 *2

f:id:akiyoko:20200501125359p:plain

理由:かっこいいから。


ちなみに、「Darcula」テーマはこんな感じの画面になります。

f:id:akiyoko:20200507035200p:plain


 

2.エディタ外観

[Editor] > [General] > [Appearance]

[Show whitespaces]にチェックを入れます。

f:id:akiyoko:20200501115211p:plain

「Leading(行頭)」「Inner(行内)」「Trailing(行末)」にもチェックが入っていることを確認してください。


理由:半角スペース、全角スペースを可視化したいから。


 

3.コード補完

[Editor] > [General] > [Code Completion]

[Match case]のチェックを外します。

f:id:akiyoko:20200501115517p:plain

理由:コード補完(Ctrl + スペース)の際に、大文字小文字を区別しないで補完してほしいから。

(参考)コード補完 - ヘルプ | PyCharm


 

4.コードの折りたたみ

[Editor] > [General] > [Code Folding]

[Fold by default]から、「Imports」のチェックを外します。

f:id:akiyoko:20200501173118p:plain

理由:import 文がデフォルトで折りたたまれていると、レビューしにくいから。


 

5.タブの表示数

[Editor] > [General] > [Editor Tabs]

[Closing Policy]の[Tab limit]を「10」から「50」に変更します。

f:id:akiyoko:20200501172330p:plain

理由:タブを 10 個以上開くと勝手に閉じちゃう設定だと使いにくいから。


 

6.フォントサイズ設定

[Editor] > [Font]

[Size]を「12」(デフォルトは「13」)くらいにしておきます。

f:id:akiyoko:20200501120518p:plain

理由:できるだけ広い範囲でコードを見たいから。


 

7.改行コード設定

[Editor] > [Code Style]

[General]タブの[Line separator]を「Unix and macOS (\n)」に変更します。macOS 版の場合は「System-Dependent」のままでOKです。

f:id:akiyoko:20200501120725p:plain

理由:macOS で編集したコードとの差異を無くしたいから。


 

8.Python コードスタイル設定

[Editor] > [Code Style]> [Python]

8.1.一行あたりの文字数設定

[Wrapping and Braces]タブの[Hard wrap at]を「100」に変更します(デフォルトは「120」)。なお、一行あたりの文字数はプロジェクトのルールに適宜合わせてください。

f:id:akiyoko:20200501123713p:plain

理由:PyCharm の自動フォーマットを使ったときに規定文字数で自動的に折り返ししてほしいから。

8.2.import文のソート

[Imports]タブの[Sort import statements]で、「Sort imported names in "from" imports」(from 節でインポートした名前をソート)にチェックを入れます。

同じく、[Imports]タブの[Structure of "from" imports]は、デフォルトの「Leave as is」から「Join imports with the same source」(同じソースでインポートを結合)に変更します。

f:id:akiyoko:20200501124326p:plain

理由:

  • import文の自動フォーマットを使用したときに、from 節内の複数 import を自動ソートしてほしいから。
  • import文の自動フォーマットを使用したときに、from 節が同一の import 文を自動で一行にまとめてほしいから。


(参考)コード・スタイル: Python - ヘルプ | PyCharm


 

9.PEP8 違反の警告

[Editor] > [Inspections]

  • [PEP8 coding style violation]
  • [PEP8 naming conversion violation]

の「Severity」を「Week warning」から「Warning」に変更。

f:id:akiyoko:20200501184523p:plain

理由:PEP8 違反の警告をワーニングに上げたいから。


(参考)最強のPython統合開発環境PyCharm - Qiita


 

10.プラグイン

[Plugins]

から、完全に好みで プラグインをインストールします。

  • CodeGlance(Sublime Text のミニマップ風プラグイン)
  • black-pycharm(black フォーマッタプラグイン)
  • IdeaVim(Vim エミュレータプラグイン)

インストールしていないプラグインは、検索して「Install」ボタンをクリックするとオンラインのリポジトリからダウンロードしてインストールすることができます。


f:id:akiyoko:20200503160741p:plain


 

VMオプション設定

[Help] > [Edit Custom VM Options...]

を選択すると、VMオプションの設定をカスタマイズするためのファイルを編集することができます。 *3

11.メモリ設定

デフォルトのヒープメモリサイズを 2GB くらいに増やしておきます。たとえば、

-Xms128m
-Xmx750m
-XX:ReservedCodeCacheSize=240m
...(略)...

となっているのを、

-Xms128m
-Xmx2048m
-XX:ReservedCodeCacheSize=240m
...(略)...

と書き換えて、PyCharm を再起動します。


(参考)高度な構成 - ヘルプ | PyCharm


 

プロジェクトツールウィンドウ設定

プロジェクト・ビューの歯車アイコンをクリックして、ツールウィンドウの設定をおこないます。
 

12.プロジェクト・ビューの表示設定

  • [Open Files with Single Click](プロジェクト・ビューからシングルクリックでソースビューを開く)
  • [Always Select Opened File](ソースビューを開くとプロジェクト・ビューに該当モジュールがフォーカスする)

にチェックを入れておきます。

f:id:akiyoko:20200501174811p:plain

理由:プロジェクト・ビューとエディタを連動させたいから。


 

日本語化

「Pleiades 日本語化プラグイン」を利用すれば、PyCharm の UI を日本語化することも可能です。ただし JetBrains 公式のものではないため、動作は保証されていないのでご注意ください。


pleiades.io

 

13.Pleiades 日本語化プラグインの導入手順

まず、「Pleiades 日本語化プラグイン」のダウンロードサイト から zip ファイルをダウンロードします(OS に合わせてダウンロードしてください)。

f:id:akiyoko:20200508043630p:plain

なお、PyCharm バージョン 2020.1 に対応した最新の Pleiades 日本語化プラグインを使用しないと動作しないのでご注意ください。 *4



zipファイルを解凍し、setup.exe(macOS の場合は setup.app)をダブルクリックしてインストーラを起動します。


f:id:akiyoko:20200508043953p:plain:w400


「日本語化するアプリケーション」の「選択」ボタンをクリックして、Windows の場合は

  • C:\Program Files\JetBrains\PyCharm Community Edition 2020.1\bin\pycharm64.exe

macOS の場合は

  • /Applications/PyCharm CE.app

を選択して、「日本語化する」ボタンをクリックします。


f:id:akiyoko:20200508043705p:plain:w400


あとは、PyCharm を再起動すれば OK です。


f:id:akiyoko:20200508043718p:plain


 

便利なショートカット集

最後に非常に便利なショートカットをいくつか紹介します。

JetBrains 公式の PyCharm チートシート

もありますが、さすがに全部覚えきれませんよね。そこで、私が特に重要と考えるショートカットを抜粋してみました。黄色で強調したショートカットだけでも覚えておくと、効率が劇的に上がりますのでぜひ活用してください。

 

コードフォーマット
Windows
macOS
説明
Ctrl + Alt + L option + ⌘ + L コードの自動フォーマット
Ctrl + Alt + O control + option + O import文の自動フォーマット

 

検索
Windows
macOS
説明
Ctrl + F ⌘ + F ファイル内検索
(Shift +) F3 ⌘ + (shift +) G ファイル内検索結果の前後を表示
Ctrl + Shift + F ⌘ + shift + F パス内検索
Alt + F7 option + F7 関数・メソッドを使用している箇所を検索して Find ウィンドウに表示
Ctrl + Alt + ↓ (↑) ⌘ + option + ↓ (↑) Findウィンドウの検索結果の前後を表示
Ctrl + Alt + ← (→) ⌘ + option + ← (→) 履歴の前後を表示
Ctrl + B ⌘ + B 関数・メソッドの宣言箇所にジャンプ

 

ファイルを開く
Windows
macOS
説明
Shift x 2 (素早く2回) shift x 2 (素早く2回) クイック検索
Ctrl + E ⌘ + E 最近開いたファイルを開く
Ctrl + Shift + N ⌘ + shift + O ファイル名でファイルを開く

 

タブ移動
Windows
macOS
説明
Alt + ← (→) control + ← (→) タブ移動

 

差分表示
Windows
macOS
説明
(プロジェクト・ビューで) Ctrl + D (プロジェクト・ビューで) ⌘ + D 別ファイルとの Diff

 

その他
Windows
macOS
説明
Ctrl + Shift + S ⌘ + ,(カンマ) 環境設定を開く
Ctrl + Shift + A ⌘ + shift + A 利用できるアクションを検索

 

まとめ

個人的に、PyCharm は Python の統合開発環境(IDE)として最強だと考えています。デフォルトの環境設定を何もイジらなくても快適に動いてくれるというのも大きな魅力のひとつが、今回のような環境設定をすると PyCharm はさらに使いやすくなります。


それでは、素敵な PyCharm ライフを!



 

宣伝

Django の本を3冊書きました。Django 開発のお供にどうぞ。

現場で使える Django の教科書《基礎編》

★ Amazon(電子版/ペーパー版)


★ BOOTH(ペーパー版)


現場で使える Django の教科書《実践編》

★ Amazon(電子版)


★ BOOTH(ペーパー版)


現場で使える Django REST Framework の教科書

★ Amazon(電子版)


★ BOOTH(ペーパー版)

*1:その他にも Educational 版があります

*2:macOS 版ではデフォルトが「Darcura」になっているようです。少なくとも私の環境では。

*3:Windows の場合は「~\AppData\Roaming\JetBrains\PyCharmCE2020.1\pycharm64.exe.vmoptions」、macOS の場合は「~/Library/Application Support/JetBrains/PyCharmCE2020.1/pycharm.vmoptions」がデフォルトです。

*4:IntelliJ IDEA / PyCharm 等 JetBrains IDE 2020.1 アップデート関連の問題と対処 | JetBrains ブログ

Windows + Python 3.8 で pip install mysqlclient が失敗する原因と対策

Windows + Python 3.8 の環境下で pip install mysqlclient が失敗する原因と対策について、備忘録をまとめておきます。

結論

Windows 10 + Python 3.8 + pip 19.2.2 以前という環境で、mysqlclient 1.4.6 の pip インストールが失敗する。その際、「Microsoft Visual C++ 14.0 is required」あるいは「include ファイルを開けません。'mysql.h':No such file or directory」といったエラーが出る。

対策としては、pip のバージョンを 19.2.3 以降にアップグレードするだけ。

なお、Microsoft Visual C++ をインストールする必要はありません。



詳細

エラー(その1)

PC に Visual C++ がインストールされていない状況では、「error: Microsoft Visual C++ 14.0 is required」というエラーが出ます。しかし、Visual C++ をインストールしても後述するエラー(その2)が出てしまい、根本解決には至りません。

《 発生条件 》
  • Windows 10
  • Python 3.8.2
  • pip 19.2.2
  • Microsoft Visual C++ 14.0 以降が未インストール
《 エラー内容 》
(venv) C:\Users\akiyoko\work\mysqlclient-test>pip install --no-cache-dir mysqlclient
Collecting mysqlclient
  Downloading https://files.pythonhosted.org/packages/d0/97/7326248ac8d5049968bf4ec708a5d3d4806e412a42e74160d7f266a3e03a/mysqlclient-1.4.6.tar.gz (85kB)
     |████████████████████████████████| 92kB 990kB/s
Installing collected packages: mysqlclient
  Running setup.py install for mysqlclient ... error
    ERROR: Command errored out with exit status 1:
     command: 'c:\users\akiyoko\work\mysqlclient-test\venv\scripts\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\akiyoko\\AppData\\Local\\Temp\\pip-install-yluhih0a\\mysqlclient\\setup.py'"'"'; __file__='"'"'C:\\Users\\akiyoko\\AppData\\Local\\Temp\\pip-install-yluhih0a\\mysqlclient\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\akiyoko\AppData\Local\Temp\pip-record-4l7b4jv9\install-record.txt' --single-version-externally-managed --compile --install-headers 'c:\users\akiyoko\work\mysqlclient-test\venv\include\site\python3.8\mysqlclient'
         cwd: C:\Users\akiyoko\AppData\Local\Temp\pip-install-yluhih0a\mysqlclient\
    Complete output (24 lines):
    running install
    running build
    running build_py
    creating build
    creating build\lib.win-amd64-3.8
    creating build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\__init__.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\_exceptions.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\compat.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\connections.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\converters.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\cursors.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\release.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\times.py -> build\lib.win-amd64-3.8\MySQLdb
    creating build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\__init__.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\CLIENT.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\CR.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\ER.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\FIELD_TYPE.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\FLAG.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    running build_ext
    building 'MySQLdb._mysql' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": https://visualstudio.microsoft.com/downloads/
    ----------------------------------------
ERROR: Command errored out with exit status 1: 
    ...(略)...


ちなみに、Visual Studio Community 2019 のインストール時に、Visual C++ を合わせてインストールすることができます(根本解決にはならないので悪しからず)。手順を以下に示します(が、やるだけ無駄ですのでご注意を)。

Visual Studio 2019 のダウンロードページ から、コミュニティ版のインストーラをダウンロードします。

f:id:akiyoko:20200420222420p:plain:w400

ダウンロードしたインストーラをダブルクリックすると、Visual Studio Installer が起動します。「個別のコンポーネント」から「Visual C++」を検索して、「C++ x64/x86 ビルドツール」を選択してインストールします。

f:id:akiyoko:20200420223318p:plain:w500

「Visual C++」がインストールできました。Windows の「アプリと機能」から確認可能です。

f:id:akiyoko:20200420223337p:plain:w400


なお、「Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019」は、https://support.microsoft.com/en-gb/help/2977003/the-latest-supported-visual-c-downloads からも exe ファイルを直接ダウンロードしてインストールが可能です。PC の環境に合わせてご利用ください(私の環境は「x64」でした)。




エラー(その2)

PC にすでに Visual C++ がインストールされていても、pip のバージョンが 19.2.2 以前だと、「fatal error C1083: include ファイルを開けません。'mysql.h':No such file or directory」というエラーが出てしまいます。

《 発生条件 》
  • Windows 10
  • Python 3.8.2
  • pip 19.2.2
  • Microsoft Visual C++ 14.0 以降がインストール済み
《 エラー内容 》
(venv) C:\Users\akiyoko\work\mysqlclient-test>pip install --no-cache-dir mysqlclient
Collecting mysqlclient
  Downloading https://files.pythonhosted.org/packages/d0/97/7326248ac8d5049968bf4ec708a5d3d4806e412a42e74160d7f266a3e03a/mysqlclient-1.4.6.tar.gz (85kB)
     |████████████████████████████████| 92kB 845kB/s
Installing collected packages: mysqlclient
  Running setup.py install for mysqlclient ... error
    ERROR: Command errored out with exit status 1:
     command: 'c:\users\akiyoko\work\mysqlclient-test\venv\scripts\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\akiyoko\\AppData\\Local\\Temp\\pip-install-kp34ucod\\mysqlclient\\setup.py'"'"'; __file__='"'"'C:\\Users\\akiyoko\\AppData\\Local\\Temp\\pip-install-kp34ucod\\mysqlclient\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\akiyoko\AppData\Local\Temp\pip-record-3csqetin\install-record.txt' --single-version-externally-managed --compile --install-headers 'c:\users\akiyoko\work\mysqlclient-test\venv\include\site\python3.8\mysqlclient'
         cwd: C:\Users\akiyoko\AppData\Local\Temp\pip-install-kp34ucod\mysqlclient\
    Complete output (30 lines):
    running install
    running build
    running build_py
    creating build
    creating build\lib.win-amd64-3.8
    creating build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\__init__.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\_exceptions.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\compat.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\connections.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\converters.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\cursors.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\release.py -> build\lib.win-amd64-3.8\MySQLdb
    copying MySQLdb\times.py -> build\lib.win-amd64-3.8\MySQLdb
    creating build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\__init__.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\CLIENT.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\CR.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\ER.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\FIELD_TYPE.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    copying MySQLdb\constants\FLAG.py -> build\lib.win-amd64-3.8\MySQLdb\constants
    running build_ext
    building 'MySQLdb._mysql' extension
    creating build\temp.win-amd64-3.8
    creating build\temp.win-amd64-3.8\Release
    creating build\temp.win-amd64-3.8\Release\MySQLdb
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -Dversion_info=(1,4,6,'final',0) -D__version__=1.4.6 "-IC:\Program Files (x86)\MySQL\MySQL Connector C 6.1\include\mariadb" -Ic:\users\akiyoko\work\mysqlclient-test\venv\include -IC:\Users\akiyoko\AppData\Local\Programs\Python\Python38\include -IC:\Users\akiyoko\AppData\Local\Programs\Python\Python38\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include" /TcMySQLdb/_mysql.c /Fobuild\temp.win-amd64-3.8\Release\MySQLdb/_mysql.obj /Zl /D_CRT_SECURE_NO_WARNINGS
    _mysql.c
    MySQLdb/_mysql.c(29): fatal error C1083: include ファイルを開けません。'mysql.h':No such file or directory
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\bin\\HostX86\\x64\\cl.exe' failed with exit status 2
    ----------------------------------------
ERROR: Command errored out with exit status 1:
    ...(略)...

 

原因

根本原因

同じ環境でも pip のバージョンによって、対応している Python のバージョンと ABIタグの組み合わせが微妙に異なっているということが分かりました。具体的には、バージョン 19.2.3 の前後で

  • pip(バージョン 19.2.2 以前)では、Python バージョン「3.8」に対応する ABIタグは「cp38m」のみ
  • pip(バージョン 19.2.3 以降)では、Python バージョン「3.8」に対応する ABIタグは「cp38」のみ

となっていたのですが、この差は、

github.com

から出てきたものと思われます。
なお、対応している Python バージョンと ABIタグの組み合わせは、

>>> from pip._internal.pep425tags import get_supported
>>> get_supported()

の実行結果から確認可能です。


一方の mysqlclient は、PyPI でソースコード形式と(コンパイル済みの C拡張を含んだ)wheel形式が配布されているのですが、最新バージョンの「1.4.6」では、Pythonバージョン「3.8」と ABIタグ「cp38」の組み合わせに対応する 「mysqlclient‑1.4.6‑cp38‑cp38‑win_amd64.whl」は用意されているものの、Pythonバージョン「3.8」と ABIタグ「cp38m」の組み合わせに対応する「mysqlclient‑1.4.6‑cp38‑cp38m‑win_amd64.whl」は用意されておらず、ソースコードをローカルでビルドしようとしてエラーになっているものと推測されます。 *1

そもそも、wheel形式の配布物が利用できないのが根本原因で、これが利用できれば C++ によるビルドは必要ないはずです。


どうしてこのような状況になるのか?

Python をインストールしたときに合わせてインストールされた pip が古いままになっている(現在は最新の Python 3.8.2 をインストールするとバージョン「19.2.3」の pip が同梱されます)、あるいは、PyCharm 内部で利用されている pip のバージョンが古い(PyCharm 2019.3 では「19.0.3」だったが、最新版の PyCharm 2020.1 では「20.0.2」となっていてこの事象は解消済み)などの状況が考えられます。




*1:非公式ですが、Python Extension Packages for Windows - Christoph Gohlke から確認可能

2019年の akiyoko blog 振り返り

明けましておめでとうございます。
毎年恒例となっている昨年のブログの振り返りから、今年もスタートです。


ちなみに 2018年の振り返りはこんな感じでした。

<過去記事>
akiyoko.hatenablog.jp


2019年の akiyoko blog 振り返り

昨年一年間にアップした記事の本数は 6本で、昨年の 12本から半減しました。2018年に引き続いてずっと Django 本の執筆をしていたからですが、アウトプットの全体量が減ったというわけではありません。カンファレンスやオープンセミナーでの登壇や新人教育、同人誌の頒布など、むしろアウトプットは激増していると思います。

ちなみに、記事の更新頻度が減ったからか、ブログ全体のアクセス数も一昨年の 3/4 ほどに減ってしまっていました。


ブログ記事ごとのアクセス数ランキング(akiyoko blog 2019年)

記事ごとのアクセス数ランキングです。2019年内のアクセス数(*1)ランキング上位 30本をリストアップしています。

なお昨年中に書いた記事 6本中、30位以内に入ったのは 1本のみでした。 *2


# 昨年比 タイトル 作成日 ポイント
1 「プロジェクトマネージャ試験」に一発合格するための三か条 - akiyoko blog 2014/10/26 74.5
2 PyCharm のオレオレ最強設定 - akiyoko blog 2017/03/10 63.4
3 「一対一」「一対多」「多対多」のリレーションを分かりやすく説明する - akiyoko blog 2016/07/31 55.5
4 初学者・初級者向け Django の学習ロードマップ - akiyoko blog 2018/12/01 39.6
5 pandas.DataFrame の列の抽出(射影)および行の抽出(選択)方法まとめ - akiyoko blog 2017/04/03 34.7
6 無料版 PyCharm で Django 開発環境を構築するまでの手順(「現場で使える 基礎 Django」本の補講その2) - akiyoko blog 2018/06/17 30.6
7 IPA「情報セキュリティマネジメント試験」に一夜漬けで合格するためのたった二つの勉強法 - akiyoko blog 2016/11/17 19.8
8 AppStore 登録前の iOSアプリを Ad-Hoc で配布してインストールする方法 - akiyoko blog 2014/08/23 18.6
9 PyCharm で Django の開発をするなら絶対やっておくべき便利な設定 - akiyoko blog 2019/12/06 16.3
10 まだ CSV の文字化けで消耗してるの?(Excel で直接開いても文字化けしない CSVファイルを Python3 で作成するスマートな方法) - akiyoko blog 2017/12/09 15.0
11 Mac の MySQL クライアントに「Sequel Pro」を使っているなら PostgreSQL クライアントは「PSequel」がオススメ - akiyoko blog 2016/07/29 14.7
12 Apple Developer Program の有効期限が切れてしまったときの対処方法 - akiyoko blog 2015/11/13 13.4
13 Django ORM の select_related, prefetch_related の挙動を詳しく調べてみた - akiyoko blog 2016/08/03 11.7
14 matplotlib のグラフに日本語を表示する方法(文字化け対応) - akiyoko blog 2017/04/11 11.3
15 Git で コミットを無かったことにする方法 (git revert の使い方) - akiyoko blog 2014/08/21 11.2
16 Video.js を使って HLS形式の動画をストリーミング再生する - akiyoko blog 2015/08/11 11.0
17 ゼロからはじめる Amazon QuickSight(AWS でお手軽データ分析 その3/3) - akiyoko blog 2017/03/15 10.4
18 GitHub の Wiki に画像を貼り付ける一番簡単な方法(Wiki リポジトリを clone しないバージョン) - akiyoko blog 2016/08/30 9.5
19 Python で MagicMock を使う - akiyoko blog 2015/01/04 8.7
20 Ansible 初心者なら、まずは Ansible Galaxy から始めてみよう - akiyoko blog 2015/12/06 8.4
21 Python でリストのソートまとめ - akiyoko blog 2014/09/26 8.3
22 Pythonで単回帰直線 - akiyoko blog 2013/06/16 7.8
23 Pandas の DataFrame の基本的な使い方 - akiyoko blog 2017/03/27 7.0
24 まだ Moodle で消耗してるの? オープンソースの Python製 LMS「RELATE」が圧倒的にカスタマイズしやくてヤバイぞ! - akiyoko blog 2017/12/19 7.0
25 ゼロからはじめる Django で ECサイト構築(その1:ECパッケージの選定) - akiyoko blog 2016/05/24 6.7
26 JavaScript で配列の添え字に文字列やマイナス値を使ったときの挙動 - akiyoko blog 2015/03/21 6.6
27 Django ORM の SQL を出力する方法まとめ - akiyoko blog 2016/08/04 6.1
28 PyCharm のデータベースツールが最強。ER図も簡単に書き出せるよ - akiyoko blog 2016/03/13 5.7
29 見よ!これが Python製の WordPress風フルスタックCMSフレームワーク「Mezzanine(メザニン)」だ! - akiyoko blog 2015/12/23 5.5
30 「あなたの趣味は?」のアンケート結果を R で因子分析してみた - akiyoko blog 2017/12/04 5.5

かなり前に書いた Python・Django 系の記事がいくつかランキングに返り咲いていたのが興味深いです。


今年の目標

今年は、引き続き Django を盛り上げていくのはもちろんのこと、今執筆している商業誌をしっかりと書き上げることを大目標にしていきたいです。今年もすでにいろいろとイベントが予定されていて忙しそうなのですが、なんとか乗り切っていきたいと思います。

今年もよろしくお願い致します。


f:id:akiyoko:20200103114643p:plain:w350

*1:純粋な PV数ではなく、作成日からの日数で割ったポイントで算出しています。

*2:作成日のところを黄色く塗っています。

PyCharm で Django の開発をするなら絶対やっておくべき便利な設定

この投稿は 「Django Advent Calendar 2019 - Qiita」 6日目の記事です。

Python 開発の IDE には「PyCharm」を激推ししている akiyoko です。
推しの理由は、以下の点が非常に有用だと感じているからです(JetBrains のステマじゃないですよん 😅)。

  • インストールしたそのままの状態で快適に使える
  • venv」(仮想環境を作成するためのモジュール)や「pip」(パッケージ管理ツール)のコマンドの使い方が分からなくても、画面からポチポチと操作できる
  • コードジャンプ機能と自動整形機能を使うことで開発効率が著しく向上する
  • デバッグ実行を使うことでコード解析が捗る


中でもデバッグ実行が便利ですよね。ライブラリの中もどんどん潜ってデバッグ実行できるので、障害解析やコードの理解が格段に捗ります。


Django の開発をする際にももちろん PyCharm を愛用しています。プライベートでは有償版の PyCharm Professional Edition を利用していますが、仕事では無償版の PyCharm CE(Community Edition)を利用しています。



PyCharm の開発元 JetBrains の 昨年の調査 によると、Webアプリ開発をするときは 30〜40%くらいの方が PyCharm(有償版・無償版を合わせて)を利用しているとのこと。私の周りのつよつよ Pythonista の方でも PyCharm を愛用している人は多いです。

この記事を書くにあたって事前に統合開発環境(IDE)の利用状況をアンケートしてみたのですが、

PyCharm の利用率が 30〜40%なのは JetBrains の調査と概ね合致します。
それにしても、VS Code の勢いがすごいですね!
Webアプリ開発ではフロントエンドまわりの面倒も見なくてはいけないことが多々あるので、JS まわりのサポートが弱い PyCharm CE(無償版)よりも、VS Code が選ばれるという状況があるのかなと感じました。皆さま、アンケートにご協力ありがとうございました 🙇‍♂️



前置きが長くなりましたが、ここから本題です。

有償版・無償版を問わず、PyCharm を利用して Django プロジェクトの開発をするなら「これだけはぜひ設定しておいてほしい」という便利な設定があります。


それは、「runserver」の実行(Run / Debug)設定 です。



この設定をすることで、

  • ワンクリックで runserver のデバッグ実行が可能
  • runserver の実行で PyCharm のターミナルツールウィンドウを専有しない

というメリットが得られます。



runserver の実行(Run / Debug)設定

では、その設定方法です。*1


Django プロジェクトのひな型を作成する際に「startproject」コマンドを実行すると、管理コマンドを実行するための「manage.py」が自動生成されますよね。

その「manage.py」を右クリックし、「Create 'manage' ...」を選択 します。なお、すでにこのプロジェクトで Run / Debug 設定をしたことがある場合は「manage.py」の右クリック時にこの選択肢が表示されないのでご注意ください(その場合は「Run」>「Edit Configurations...」メニューから Run / Debug の設定をおこなってください)。

f:id:akiyoko:20191203080923p:plain

Run / Debug 設定画面が表示されるので、「Parameters」に「runserver」と入力して、「OK」をクリック します。この際、「Name」には、分かりやすいようにたとえば「runserver」と入力しておけばよいでしょう。

f:id:akiyoko:20191203080931p:plain:w500

Run / Debug 設定を済ませると、ナビゲーションバーの右側に「runserver」との表示がされます。

f:id:akiyoko:20191203080957p:plain

「runserver」の右側の虫アイコンをクリックすればデバッグ実行が開始されます。

f:id:akiyoko:20191203081003p:plain:w400


デバッグ実行を開始すると、デバッグツールウィンドウ(Debug タブ)が起動してコンソールにログが出力されます。コードの途中にブレークポイントを置いておけば、コードが実行されたときにそこで中断されて変数などがデバッグができるようになります。

f:id:akiyoko:20191204003907p:plain


デバッグツールウィンドウの使い方については、公式ヘルプの「デバッグツールウィンドウ - ヘルプ | PyCharm」を参照してください。



いつもなら runserver を実行するのに

> python manage.py runserver

というコマンドをターミナルツールウィンドウ(Terminal タブ)を使って実行するところを、デバッグ実行はそれとは別のデバッグツールウィンドウ(Debug タブ)上で動作するため、ターミナルのウィンドウを専有することがありません。このため、makemigration、migrate、createsuperuser などの管理コマンドを実行するために、わざわざターミナル上で実行している runserver を停止して、その後 runserver を再実行する・・なんてことをする手間が不要になるのです。


これは便利ですよね〜 😚




おまけ ①

ここで、便利な裏技(?)をひとつ紹介します。

デバッグ実行中にブレークポイントでコードの実行を止めた状態ではデバッグツールウィンドウに「Debugger(デバッガ)」と「Console(コンソール)」という2つのタブが表示されます。ここで、「Console」タブをクリックして、Python ロゴのアイコン(Show Python Prompt)をクリックしてみてください。


f:id:akiyoko:20191205033219p:plain:w550


すると、任意の Python コードが、止めたコード内で実行できるようになります。
ハイ、便利〜 😆


おまけ ②

runserver 実行時にオプションを指定したい場合がありますよね。

そんな場合は、ナビゲーションバー右側の「runserver」をクリックし、「Edit Configurations...」を選択して Run / Debug の設定画面を開きます(「Run」>「Edit Configurations...」メニューからでも開くことができます)。

f:id:akiyoko:20191205041253p:plain:w500


「Parameters」に設定している「runserver」のところを「runserver --settings xxx」などと書き換えることで、実行時のオプションが指定可能です。

f:id:akiyoko:20191205041641p:plain

また、「Environment variables」から「DJANGO_SETTINGS_MODULE」などの環境変数を設定することも可能です。


おまけ ③

runserver の他によく利用する Django の管理コマンドとして、「test」(ユニットテストの実行)があります。

今回紹介した runserver の実行設定と同じようにワンクリックで Django プロジェクトのユニットテストを実行したい場合は、次のように「runserver」の設定をコピーするのが簡単です。

コピーしたら、「Parameters」を「test」に書き換えます(「Name」も適宜「test」などと書き換えます)。

f:id:akiyoko:20191205041944p:plain


あとは、「Run」アイコンか「Debug」アイコンをクリックするだけで Django プロジェクトのユニットテストが実行できるようになります。

f:id:akiyoko:20191205043241p:plain:w500



おまけ ④

ここまでくると、Coverage.py を利用したカバレッジもワンクリックで実行したいですよね。

こんな感じで Run / Debug 設定をすれば OK です。

f:id:akiyoko:20191205042003p:plain

f:id:akiyoko:20191205042020p:plain

ポイントは、「Script path」のところを「Module name」に変更してから、「coverage」と手入力するところですかね(仮想環境下にインストールされた coverage の絶対パスを「Script path」に指定してもよいですが)。もちろん、pip で coverage をインストールしておいてくださいね。

ちなみに、有償版の PyCharm Professional では、PyCharm に内蔵された独自のカバレッジ機能を使ってワンクリックでカバレッジを取得することができます。*2



まとめ

PyCharm で Django の開発をするなら、runserver の実行(Run / Debug)設定をやっておきましょう。

  1. 「manage.py」を右クリックして「Create 'manage' ...」を選択
  2. Run / Debug 設定画面で「Parameters」に「runserver」と入力して「OK」

これだけです。ほんの5分足らず(もしかしたら1分くらいで??)で設定は終わります。

runserver のデバッグ実行をポチッとワンクリック(ショートカットもあります)でスタートできる便利さを味わうと、もう PyCharm から離れられませんよ〜 😙


Enjoy Django & PyCharm !! 😉


f:id:akiyoko:20191206074253p:plain




明日は、nogissh さんの「Django Advent Calendar 2019 - Qiita」7日目の記事です。よろしくお願いします。



 

宣伝

Django の本を3冊書きました。Django 開発のお供にどうぞ。

現場で使える Django の教科書《基礎編》

★ Amazon(電子版/ペーパー版)


★ BOOTH(ペーパー版)


現場で使える Django の教科書《実践編》

★ Amazon(電子版)


★ BOOTH(ペーパー版)


現場で使える Django REST Framework の教科書

★ Amazon(電子版)


★ BOOTH(ペーパー版)

*1:PyCharm のバージョンは Community Edition(無償版)の「2019.3」(現時点での最新バージョン)です。

*2:ビルトイン開発者用ツール - 機能 | PyCharm

DRF を使うなら必読!『現場で使える Django REST Framework の教科書』を技術書典7 で頒布します

9月22日に開催される 技術書典7 に、「あきよこブログ」として 4回目のサークル参加をします。

みなさん安心してください、今回も Django 本ですよ 😁


新刊は『現場で使える Django REST Framework の教科書』です。


f:id:akiyoko:20190908041824p:plain:w400



「Django REST Framework(通称 DRF)」にピンと来ない方がいるかもしれませんが、「Django」の上に乗っかった、API を作ることに特化したライブラリです。つまり DRF は、Python で REST API を作るためのフレームワークです。SPA(シングルページアプリケーション)やスマホアプリのバックエンドとして利用されることが多いです。Django も DRF も日本ではあまり知られていませんが、実は海外では結構有名です。

どんな内容?

技術書典6 で頒布した前作『現場で使える Django REST Framework の薄い本』にかなり大幅な加筆・改訂を加えて、「Django の教科書」シリーズとしてリニューアルしました。前作の124ページに対して、今作は204ページと大ボリュームの仕上がりになっています。

今のところ、同人誌を含めて 日本でオンリーワンの「Django REST Framework」の日本語書籍 になっています。

内容は、Django REST Framework を現場で使う際に必要となる基礎知識と発展的な Tips をまとめたものになっています。なお、Django REST Framework は Django をベースにしている部分があるので、Django についての解説に紙面を割いているところもあります。

前半は DRF の概要や全体像、コンポーネントごとの仕組みや使い方、セキュリティや認証などの基礎知識を座学で進めていきます。後半はチュートリアルおよび発展的な Tips という構成になっています。

後半のチュートリアルでは、Django も Django REST Framework も何にも分からないという方でもちょっとした SPA が作れるように、Django REST Framework と Vue.js を使った SPA のサンプルプロジェクトを2つ、簡単なものと少し難しめなものを用意しました。 これを手本に写経すれば、REST API を使った Webアプリケーションの仕組みが何となく掴めるでしょう。

目次

f:id:akiyoko:20190907201801p:plain:w500
f:id:akiyoko:20190908101706p:plain:w500

対象読者

対象読者としては、

  • Django は何となく分かるが、Django REST Framework は初めてという方
  • Django REST Framework のまとまった日本語情報を手に入れたい方
  • Django REST Framework + Vue.js で SPA を構築したい方
  • 現場で本格的に Django REST Framework を使いたい方

を想定しています。

最低限必要の知識としては「Django の仕組みが何となく理解できていること」です。Django 公式チュートリアルDjango Girls チュートリアル をひと通り終えたくらいであれば、何とか理解できるレベルになっているかと思います。拙著『現場で使える Django の教科書《基礎編》』を読み終えたくらいの知識があれば万全ですが、『現場で使える Django の教科書《実践編》』レベルの知識は不要でしょう。


前作の薄い本と何が違うの?

ざっと挙げるとこんな違いがあります。

  • 本文が204ページに大幅増(前作の124ページから1.6倍!)
  • DRF のコンポーネントの解説が充実
  • ユニットテストの章を新設
  • Tips(発展編)のトピック数が 5 ⇒ 13 に(ページ数は 11p ⇒ 31p)
  • 各種ライブラリは最新バージョンに対応

一番の特徴は、コンポーネントの解説を充実させたことです。「モデル・シリアライザ・ビュー・URLconf」で1つの章になっていたのを、それぞれ独立した章として新設しました。ページ数では、モデル 1p ⇒ 18p、シリアライザ 8p ⇒ 18p、ビュー 14p ⇒ 25p、URLconf 5p ⇒ 8p とそれぞれ大幅に増えています。特に、シリアライザは DRF の中でも大きな部分を占めるので、図を増やしてイチから分かりやすい解説を目指しました。

DRFではシリアライザとビューが特に重要と考えています。シリアライザはフォームと同様に使えるように作られたコンポーネントで、使うのにコツが必要です。一方、DRFのビューはキモの部分で、通常のビューとどう違うのか?どのクラスを継承すればよいのか?を理解する必要があります。新刊を読めばそのあたりもスッキリ理解できるようにいろいろと追記しました。

あと、Django 初心者に少し優しくなりました。特に、前作ではモデルについての説明を「Django と同じ。以上!」としていたのを、きちんと章立てをして解説しています。内容は『現場で使える Django の教科書《基礎編》』からのほぼ抜粋になりますが、スッキリとまとめ直した上で DRF 向けに修正を加えています。

新設した「ユニットテスト」の章もぜひ読んでほしいです。〆切ギリギリで入れるかどうか悩みましたが、教科書としてユニットテストは必須と判断しました。11pと短いながらも、Djangoのユニットテストの特徴やフロー、DRFでの具体的な書き方など、うまくまとめられたと自画自賛しています。

最終章のTips集では、

  • Browsable API
  • APIドキュメント
  • フィルタリング
  • ページネーション

などの機能解説や、

  • 関連モデルの扱い
  • フィールドの追加
  • ネストしたURL
  • カスタムアクション
  • トランザクション
  • 排他制御

など「こんなときはDRFではどうすればいいの?」という疑問にお答えしています。

「Djangoの教科書」シリーズの名に恥じないようDRFの基礎知識やノウハウをできる限り網羅しつつ、DRF初心者にも分かりやすく読めるように書きました。現場でDRFを使っている人、これから使う人の手元に置いてもらえるように頑張って書いたので、とにかく一度、手に取って読んでみていただければと思います。



そして、「そこまで言われても、前作の薄い本買っちゃったしなぁ。どうしよう・・」と悩んでいるあなたに朗報です。

前作『~の薄い本』を技術書典7に持ってきていただいた方、先着50名に、なんとワンコイン(500円)で新刊を買えるサービスを実施します!


f:id:akiyoko:20190908122859p:plain:w400

ただし、お一人様1冊限りでお願いします(薄い本にはスタンプを押させていただきますのでご了承ください)。


頒布本情報

既刊の『現場で使える Django の教科書《基礎編》』『現場で使える Django の教科書《実践編》』を含めて、「Django の教科書」シリーズが3冊揃っています。

なおいつものように「会場特別価格」です。


f:id:akiyoko:20190917121916p:plain:w300


f:id:akiyoko:20190917121947p:plain:w300


実は今回の技術書典に合わせて《実践編》を1年振りにリニューアルして、Django 2.2 対応等をおこないました。


これらの既刊については、Amazon や BOOTH で電子版とペーパー版が販売中です。


◆ 現場で使える Django の教科書《基礎編》 - Amazon(電子版・ペーパー版)

現場で使える Django の教科書《基礎編》

現場で使える Django の教科書《基礎編》

◆ 現場で使える Django の教科書《基礎編》 - BOOTH(ペーパー版)
現場で使える Django の教科書《基礎編》【紙の本】 - あきよこブログ(akiyoko blog) - BOOTH


◆ 現場で使える Django の教科書《実践編》 - Amazon(電子版)

現場で使える Django の教科書《実践編》

現場で使える Django の教科書《実践編》

◆ 現場で使える Django の教科書《実践編》 - BOOTH(ペーパー版)
現場で使える Django の教科書《実践編》【紙の本】 - あきよこブログ(akiyoko blog) - BOOTH



頒布場所

日時は 9/22(日)11時から17時まで、頒布場所は池袋サンシャインシティ3F 展示ホール「お74C」の「あきよこブログ」です。

見本誌を置いてますので、立ち読みだけでもお気軽にどうぞ。

f:id:akiyoko:20190917122645p:plain



最後に

余裕をもって始めたはずの執筆ですが、急遽、《実践編》の改訂と増版をしたのもあり、今回もギリギリの入稿になってしまいました。出すものは全部出した感があるので、自分なりにスッキリしています。技術書典当日は晴れやかに迎えられそうです!

DjangoCongress JP 2019 で「現場で使える Django のセキュリティ対策」というタイトルで登壇してきました

akiyoko です。

昨日の DjangoCongress JP 2019(Day 1 カンファレンスデー)で「現場で使える Django のセキュリティ対策」というタイトルで登壇してきました。その報告です。


発表資料は こちら にアップしています。


発表の動機

仕事の現場でもっと Django を使ってほしい という想いから、この発表を思い立ちました。Django 普及の突破口のひとつとして、まずはセキュリティの懸念を取り払うことが重要なのでは?と考えたのです。

Python が企業でも幅広く使われるようになったことや書籍が充実し始めたことで、日本でもようやく Django が注目されるようになりました。4月に待望のバージョン2系の LTS がリリースされ、ますます現場で Django が盛り上がることが予想されますが、導入検討の際にネックになるもののひとつに「セキュリティ」への懸念があります。私は現在、ある Django プロジェクトの立ち上げに携わっているのですが、そこで実際によく言われたのが「Django ってセキュリティ的にどうなん?」 でした。日本では(特に SIer 界隈では)Django がまだあまり知られていないので、そのような疑問が出てくるのは当然といえば当然かもしれません。

一方の開発者からすると、フルスタック(全部入り)の Django にはデフォルトでセキュリティ対策も含まれていますが、そのあたりの理解が中途半端だと、リリースした Webアプリケーションが悪意ある攻撃者の格好の餌食になってしまいかねません。そうならないためにも、Django のセキュリティ事情については開発前から(もちろん開発中でも)きちんと把握しておきたいところです。

そこで今回、IPA(情報処理推進機構)が注意喚起情報として公表している「安全なウェブサイトの作り方」という冊子にまとめられた代表的な脆弱性の概要と、それらの脆弱性に対して Django では具体的にどのような対策をしているのかについて解説することにしました。これによって発注側企業においてはセキュリティの懸念が払拭され、一方の開発側企業においてはセキュリティ施策のヒントとして活用されることを期待しています。

対象者

対象者は、Django の導入を検討している方、および Django を使った Webアプリケーション開発者 を想定しています。なお、Django 初級者の方にも十分理解できる内容になっていると思います。

Webアプリケーションの基本的な知識(特に Cookie を使ったセッション管理や HTTPヘッダなどの知識)があれば、セキュリティの知識についてはほぼゼロ(用語を何となく聞いたことがあるレベル)でも問題ありません。CSRF などの重要な、そして重要な割にあまりよく理解されていないものについては、「CSRF(しーさーふ)って何?」というレベルの人にも分かるように基本から解説しています。

ポイント

メインの話題として

① Webアプリケーションのセキュリティ対策ってそもそも必要なの?
② 「これだけは絶対やっとけ」的な基準はある?
③ フルスタック(全部入り)の Django を使えばセキュリティ対策もまるっと万事解決?

の三点について話しました。
詳細についてはスライドをご覧ください。

発表の準備

昨年の LT でド緊張して失敗した苦い思い出があるので、今回はまず、心構えから入りました。事前に読んだのは、たまたま見つけた オリラジ中田さんの講演会ログ です。要約すると、プレゼンでは「カンペを読まない」「言い訳しない」「練習をサボらない」の3つのタブーがあるということです。中でも、人前で練習をすることが「練習」でそれ以外は「練習」ではない というのはまさにその通りだと思い、リハーサルをなるべく多くこなそうと考えていました。

発表の内容については CFP を出した頃に目次レベルまで固めていたのですが、実際に発表資料を準備し始めたのは仕事の関係もあって GW の終盤からとなりました。しかしこれはちょっと遅すぎました。資料が完成したのは本番5日前。そこから2回、会社の Django 経験者やコンサルタントのメンバーの前、そして現プロジェクトメンバーの前でのリハーサルをおこないました。メンバーからのフィードバック、そして自身の反省から、資料がブラッシュアップされていき、話した方がよいこと・話さなくてよいことが明確になり、想定問答も明らかになって私にとっては良いこと尽くめでした。もっとリハーサルをしたかったのですが、何度も集まってもらうのもメンバーの負担になるのと、直前にフィードバックをもらっても反映できない、余計に混乱してしまうと感じたので、これが限界だったのかも知れません。あとはブツブツ独り言を繰り返し、本番の流れをイメージしていきました。


フィードバックの中で、「図を指差しで説明するよりもレーザーポインターでやった方がいい」と言われて急遽買ったのがこれ。パワポのページ送りもできます。本番前日の夕方に届きました。しかしこれが、当日あのような事件を引き起こすことになろうとは。。


あと、GW 中盤に引いた風邪がずっと長引いていたので体調を整えるために前日夜にマッサージに行ったのですが、強かったのか余計に首を痛めてしまいました。


発表はどうだった?

「発表前にやることリスト」を作っていたので、それを淡々とこなすことで緊張はギリギリのところで抑えられていました。

しかし、プレゼン開始直後に事件が起きました。前日の動作チェックでは問題なかったレーザーポインターがページ送りができなくなり、直前に使用を諦めました。これで緊張のコップから水が少し溢れてしまいました。。


f:id:akiyoko:20190519130935p:plain:w180

この事件がきっかけとなって冒頭の10分はガチガチでした。途中からあきらめの境地に至ってから割と話せるようになったと思いますが、そこで何とか踏み止まれたのも事前のリハーサルのおかげです。あれが無ければもうボロボロの結果になったに違いありません。協力してくださった皆さん、本当にありがとうございました。



質問

想定よりも時間がかかってしまいましたが、発表は42分頃に終わりました。そこで出た質問について補足します。

Q.{% csrf_token %} タグを入れ忘れてしまうのを防ぐ方法はないのか?

POST リクエストを送信する form 要素に {% csrf_token %} タグを入れ忘れると、403 エラーが出ます。しかしながら、CsrfViewMiddleware を無効にするなり @csrf_exempt デコレータを利用したりすると、CSRF 検証はされずに脆弱性が露呈してしまいます。会場では、設定ファイルのセキュリティチェックをしてくれる「python manage.py check --deploy」を実行すれば CsrfViewMiddleware が無効化されていることをチェックできるかも知れないと回答しましたが、それを改めて検証してみました。

実際に CsrfViewMiddleware を「MIDDLEWARE」からコメントアウトして check コマンドを実行すると、期待通りに CsrfViewMiddleware が無効化されているという警告が出ました。

(venv) $ python manage.py check --deploy
...(略)...
?: (security.W003) You don't appear to be using Django's built-in cross-site request forgery protection via the middleware ('django.middleware.csrf.CsrfViewMiddleware' is not in your MIDDLEWARE). Enabling the middleware is the safest approach to ensure you don't leave any holes.


いい感じですね。


反響

いろいろと反響をいただきましたが、一番驚いたのがこれです。


あの徳丸さんにTweetしてもろた!😲マジか!

徳丸さんは、私の発表でも紹介した Webアプリのセキュリティ対策の金字塔「徳丸本」こと『体系的に学ぶ 安全なWebアプリケーションの作り方 第2版』の著者です。現場でも必読書になっています。



あと夕方頃に気付いたのがこちら。Speaker Deck のスライド資料が、はてなブックマークのホットエントリーに入っていたみたいです。


最後に

今年の DjangoCongress JP 2019(Day 1 カンファレンスデー)はセッションもパーティーも大盛況で、大御所イベントのような安定感がありました。これも、ずっと前からこの日のために動いてくれていたスタッフの皆さんの準備、運営、そして情熱のおかげです。本当にありがとうございました。昨年も参加させていただき、そして今年はセッション発表の機会をいただいて、このような素晴らしい場で発表側に回れたことは大変光栄に感じています。おかげさまで昨年のリベンジもできました。またたくさんの方にセッションを聴きに来ていただき、嬉しくそして心強かったです。機会があれば来年もチャレンジしてみたいと思います。




おまけ

じゃんけん大会で一番人気だった『現場で使える Django REST Framework の薄い本』は、BOOTH というオンラインショップから購入可能です(紙の本のみ)。

akiyoko.booth.pm


DjangoCongress に来るくらいの人はもうほとんど持ってる or 知ってるという噂もありますが(笑)、『現場で使える Django の教科書』シリーズ(基礎編・実践編)も BOOTH で購入できます。

akiyoko.booth.pm


『現場で使える Django の教科書』シリーズ(基礎編・実践編)は、Amazon でも販売しています(電子版もあり)。

現場で使える Django の教科書《基礎編》

現場で使える Django の教科書《基礎編》

現場で使える Django の教科書《実践編》

現場で使える Django の教科書《実践編》