aspnet-codegeneratorを実行すると「You must install or update .NET to run this application.」が出たときの対処法

対象バージョン

.NET SDK 9.0.305, Mac OS X 13.7

dotnet --info の表示 .NET SDK: Version: 9.0.305 Commit: 3fc74f3529 Workload version: 9.0.300-manifests.ddedba1d MSBuild version: 17.14.21+8929ca9e3

ランタイム環境: OS Name: Mac OS X OS Version: 13.7 OS Platform: Darwin RID: osx-x64 Base Path: /Users/kimihito/.local/share/mise/installs/dotnet/9.0.305/sdk/9.0.305/

インストール済みの .NET ワークロード: 表示するインストール済みワークロードはありません。 新しいマニフェストをインストールするときに loose manifests を使用するように構成されています。

Host: Version: 9.0.9 Architecture: x64 Commit: 893c2ebbd4

.NET SDKs installed: 9.0.305 [/Users/kimihito/.local/share/mise/installs/dotnet/9.0.305/sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 9.0.9 [/Users/kimihito/.local/share/mise/installs/dotnet/9.0.305/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 9.0.9 [/Users/kimihito/.local/share/mise/installs/dotnet/9.0.305/shared/Microsoft.NETCore.App]

Other architectures found: None

Environment variables: DOTNET_ROOT [/Users/kimihito/.local/share/mise/installs/dotnet/9.0.305]

global.json file: Not found

Learn more: https://aka.ms/dotnet/info

Download .NET: https://aka.ms/dotnet/download

起こったこと

dotnet tool install dotnet-aspnet-codegenerator --global でインストール後に、dotnet aspnet-codegenerator を実行すると以下のエラーが出た

You must install or update .NET to run this application.

App: /Users/kimihito/.dotnet/tools/dotnet-aspnet-codegenerator
Architecture: x64
Framework: 'Microsoft.NETCore.App', version '8.0.0' (x64)
.NET location: /Users/kimihito/.local/share/mise/installs/dotnet/9.0.305

The following frameworks were found:
  9.0.9 at [/Users/kimihito/.local/share/mise/installs/dotnet/9.0.305/shared/Microsoft.NETCore.App]

.NET 9 を入れたはずなのに、.NET 8を要求されているよう。

解決法

dotnet tool install--allow-roll-forward オプションを付与することで解決した。

具体的には

dotnet tool install dotnet-aspnet-codegenerator --allow-roll-forward --global とした

関連Issue

github.com

Django 6.0 に追加される機能からみる、Djangoのコア機能への考え方

Django 6.x Streering Council の一人である Carlton Gibsonさんが Django 6.0 への機能についてブログを書いていました

Looking forward to Django 6.0 • Buttondown

Django 6.0のアルファ版リリースは 2025-09-17 を予定しています

Django 6.0 に追加される機能

ブログ記事には以下の3点が記述されています

機能としてはそれぞれ別ですが、共通していることがあります。 それは「すべてサードパーティライブラリの機能をDjangoの機能として取り込んだ」ことです。(注: 同じインターフェースとは限らない)

これらのパッケージはリリース済みのDjangoのバージョンでも利用ができます。

Djangoの「コア機能」とはなにか

先のブログ記事の作者である、CarltonさんはこのDjangoの「コア機能」への考えについて別の記事を書いています。

Thoughts on Django’s Core • Buttondown

概要として

  • Djangoの良さは、「時間ベースのリリーススケジュール」、「APIの安定性」、「フェローシッププログラム」である

  • 機能が追加されるほど、メンテンス対象の範囲が増えてしまう

  • 新しい機能はまずはサードパーティから始めよう

  • Djangoの機能となると、Djangoのリリーススケジュールに従うことになる。

最後の2点は、Djangoの公式ドキュメントにも同様の記述があります。

Djangoの「変化」

Djangoについてよく耳にする批判の一つが「変化が遅い」「新しい機能が追加されない」というものです。確かに、他のWebフレームワークと比較すると、毎回のリリースで大きな新機能が追加されることは少ないかもしれません。

しかし、これは本当に「変化がない」ということなのでしょうか?Django 6.0の例を見ると、実際には3つもの重要な機能が追加されています。問題は「変化の見せ方」や「変化のアプローチ」が他のフレームワークと根本的に異なることなのです。

これまでCarltonさんのブログ記事の内容からみえるように、Djangoのコアに入ることはある種「枯れているか」を大切にしており、「変化」でなく「置き換え」とすることでDjangoの開発が進められていることがわかります。

まとめ

Django 6.0は「進化の仕方」を私たちに示しています。新しい機能を追加することと、実験的な機能を追加することは同じではありません。Djangoは常に進化していますが、その進化は慎重で、実証的で、長期的な視点に基づいています。 「変化がない」のではなく「変化の仕方が違う」のです。そして、この違いこそが、Djangoが20年にわたって多くの開発者に愛され続けている理由なのかもしれません。

余談ですが JavaScriptライブラリのhtmxにも似たような考えを表明した記事があり、こうした考え方への支持が一定数はあるのかもしれません。

ダラダラと書いてしまいましたが、Django 6.0のリリースが楽しみです!

Djangoの署名付きCookieをテストする方法

この記事のDjangoのバージョンは4.2になります。

署名付きCookieの設定

Djangoで署名付きCookieをセットする際は、set_signed_cookieメソッドを使用します。

from django.http import HttpResponse

def my_view(request):
    response = HttpResponse("Hello, World!")
    response.set_signed_cookie('user_preference', 'dark_mode', salt='my_salt')
    return response

署名付きCookieのテスト方法

署名付きCookieが正しくセットされているかをテストしたい場合、django.core.signing.get_cookie_signerを使用することができます。

実際の値は django.core.signing.get_cookie_signer の返り値である django.core.signing.Signerunsign メソッドを利用します。

テストコードの例

from django.test import TestCase, RequestFactory
from django.core.signing import get_cookie_signer, BadSignature
from myapp.views import my_view

class SignedCookieTestCase(TestCase):
    def setUp(self):
        self.factory = RequestFactory()
    
    def test_signed_cookie_is_set_correctly(self):
        # ビューを呼び出してレスポンスを取得
        request = self.factory.get('/')
        response = my_view(request)
        
        # Cookieが設定されているかを確認
        self.assertIn('user_preference', response.cookies)
        
        # 署名付きCookieの値を検証
        cookie_value = response.cookies['user_preference'].value
        signer = get_cookie_signer(salt='my_salt')
        
        # 署名を検証して元の値を取得
        try:
            original_value = signer.unsign(cookie_value)
            self.assertEqual(original_value, 'dark_mode')
        except BadSignature:
            self.fail("Cookie signature is invalid")

重要なポイント

saltの指定は必須です。get_cookie_signerを使用する際は、set_signed_cookieで使用したのと同じsaltを指定してください。

# set_signed_cookieで使用したsaltと同じものを指定
signer = get_cookie_signer(salt='my_salt')

調べた理由

django.http.HttpRequest.get_signed_cookieユニットテストで利用したかったのですが、うまく使うことができませんでした。

django.http.HttpRequest.get_signed_cookie のコードを見て、上記の実装方法があることを理解し、ユニットテストで利用しています。

まとめ

  • set_signed_cookieで署名付きCookieを設定
  • テスト時はget_cookie_signerを使って署名を検証
  • saltの指定を忘れずに

miseでPythonがインストールできない問題を解決した

小ネタです。

mise install python@3.12.11 を実行したところ以下のエラーが発生

mise ERROR git branch --show-current failed
mise ERROR command ["git", "-C", "/Users/kimihito/Library/Caches/mise/python/pyenv", "-c", "safe.directory=/Users/kimihito/Library/Caches/mise/python/pyenv", "branch", "--show-current"] exited with code 128

「pyenvなんて使ってないけどなぁ」と思いつつmiseのIssueを検索。すると似たような問題に遭遇している人を発見。

github.com

ここのコメント にあったように

$ mise cache clear
$ mise cache prune

を実行した後に再度 mise install python@3.12.11 を実行するとうまくいった。

uvのおかげでdjangoの関連パッケージにプルリクエストを送りやすくなった

最近はDjangoに新しいバージョンが出ると、その対応ができていることを示すプルリクエストを作成しています。高速なPythonパッケージマネージャであるuvを使うことで、このプロセスがとても簡単になりました。

2024年の例として、django-storagesDjango 5.1 対応のプルリクエストを出すときに行った手順を紹介します。 https://github.com/jschneier/django-storages/pull/1444

やったこと

  1. リポジトリをforkする
  2. uv venv を実行して仮想環境を作成(従来の方法より高速で依存関係の解決も正確です)
  3. 仮想環境に入る
  4. django-storagesはtoxを使っている。手元にtoxがないので pip install tox を実行する
  5. Django 5.1をtoxのリストに追加するコミットを作る コミット内容
  6. プルリクエストを作成する プルリクエスト

Python歴が短い自分にとって、uvの高速な環境構築と依存関係の解決は大きな助けになっています。特に uv venv コマンド一つで清潔な環境が素早く作れるので、気軽にオープンソースへの貢献ができます。

Django自体の変化が少ないため、こうした対応をしなくても動くことが多い(実際django-storagesへのプルリクエストではパッケージ内のコードは変えていない)です。 ただ、明示的に対応バージョンを記載しておくことでユーザーにとってはメリットが大きいのかなと思っています。

注意点

こうした貢献は簡単ですが、同時に安易にプルリクエストを乱発することはパッケージのメンテナに負担をかけることになるので、以下のポイントを考慮するようにしています。

  • 本当に必要な変更か確認する(すでに誰かが同様のPRを作成していないか)
  • テストが通ることを確認してからPRを出す
  • ドキュメントの更新が必要な場合は一緒に行う
    • 前述の通りCHANGELOGの変更を忘れていました。反省。
  • メンテナが理解しやすいように変更内容を明確に説明する
    • 今回の例にあるプルリクエストにも説明がありませんでした。こちらも反省。

メンテナの時間と労力を尊重する姿勢も大切にしつつ、貢献していきたいです。

HerokuデプロイでGitエラー「bad line length character: fata」の解決方法

問題の概要

Herokuに新しく作成したアプリケーションにgit pushでデプロイしようとした際に、以下のようなエラーが発生しました

Enumerating objects: 14718, done.
Counting objects: 100% (14718/14718), done.
Delta compression using up to 16 threads
Compressing objects: 100% (6495/6495), done.
fatal: protocol error: bad line length character: fata
Writing objects: 100% (14718/14718), 17.62 MiB | 1007.00 KiB/s, done.
Total 14718 (delta 7769), reused 14137 (delta 7392), pack-reused 0
fatal: the remote end hung up unexpectedly
error: failed to push some refs to 'https://git.heroku.com/example.git'

「bad line length character: fata」というエラーメッセージが表示され、Herokuへのデプロイが失敗します。

原因

この問題は、macOSでGitバージョン2.39.3を使用している場合 に発生します

解決方法

Gitのバージョンを2.39.3より上位のバージョンにアップデートすることで解消しました。

参考情報

help.heroku.com

Herokuサポートページにも同様の情報が記載されていますが、Herokuのアカウントがないと閲覧できなかったのでブログ記事にしました

django-rules:has_permの罠とその解決策

TL;DR

django-rulesとは

Djangoで権限管理をしたい場合、Djangoに内蔵されている権限と認可機能を利用したいと考えると思います。

しかし、このデフォルトの機能は権限をデータベースのレコードに保存するため、取り回しが面倒です。

Ruby on Railsでよく使われるPunditPHPのLaravelにある認可のしくみ のようにデータべースのレコードでなく、インスタンス同士で比較する形をDjangoでも実現したい場合に便利なのがdjango-rulesです。

django-rulesに関しては以下の記事が参考になります。

なお、Djangoの認証認可については id:hirokiky さんのPyconjp 2017のスライド もわかりやすいです。(最終的に自作していてすごい)

django-rulesの has_perm の問題点

さて、ここから本題です。 django-rulesにはインスタンス同士の比較だけでなく、前述したDjango内蔵している権限と認可機能とも統合できるメソッドがあります。それが、 has_perm です。

このhas_permというメソッド名、Djangoが持っているメソッドと同名です。

django-rulesのREADMEにあるように以下の設定をすることで

# settings.py
AUTHENTICATION_BACKENDS = (
    'rules.permissions.ObjectPermissionBackend',
    'django.contrib.auth.backends.ModelBackend',
)

django-rulesで書いたルールとDjangoの権限と認可機能を透過的に利用することができます。

これは便利な一方で、意図しないデータべースのアクセス増加を引き起こす場合があります。

具体的には :

  1. has_permメソッドが呼ばれると、Djangoは設定された認証バックエンドを順番に試します

  2. rules.permissions.ObjectPermissionBackendが処理を試みます

  3. 該当するルールがない場合や、結果がFalseの場合、次のdjango.contrib.auth.backends.ModelBackendに処理が移ります

  4. ModelBackendauth_permission テーブルをチェックするためのクエリを発行します

AUTHENTICATION_BACKENDSの処理を行っているコードはこちら(2025-03-27現在のLTSである4.2のもの)

特にdjango-rulesが提供するカスタムテンプレートタグ has_permをテンプレート内で利用すると、テンプレートのレンダリング中にデータべースへのアクセスが発生する原因になります。

解決策: test_rule を使う

django-rulesが提供した範囲内で権限チェックを行えるようRuleSet.test_rule というメソッドを提供しています。これを使うことで、Djangoの認証バックエンド連鎖を経由せず、django-rulesで定義したルールだけをチェックできます。

このtest_ruleを呼び出すためのカスタムテンプレートタグ test_ruleも用意 されているので利用することができます。

おわりに

てっきり has_permdjango-rulesのRuleSet内の権限チェックで完結すると思い、Django Templateで呼び出したところ急激にデータべースの負荷があがったという失態を犯してしまったのでした…

この記事が他の方に役立てば幸いです。