IntelliJ IDEA初心者です。
問題
build.gradle.ktsのdependanciesにarrowを追加したがimportが認識しない。
ビルドしなおしてもダメ。
ChatGPTに教えてもらった。
方法
画面右上の歯車マークの下のベルマークの下の謎アイコンをクリックする。
(よく見るとゾウさんマーク?)
Gradleのタブが開く。
一番左の更新ボタンを押すとリロードされ反映される。
IntelliJ IDEA初心者です。
build.gradle.ktsのdependanciesにarrowを追加したがimportが認識しない。
ビルドしなおしてもダメ。
ChatGPTに教えてもらった。
画面右上の歯車マークの下のベルマークの下の謎アイコンをクリックする。
(よく見るとゾウさんマーク?)
Gradleのタブが開く。
一番左の更新ボタンを押すとリロードされ反映される。
クラス変数はインスタンスメソッドから利用する場合混乱しやすいため注意が必要。
selfでアクセスする場合、インスタンス変数 -> クラス変数の順で探しに行くため、
クラス変数しかない状態でselfで代入すると、インスタンス変数が作成されてしまい、
以降selfではインスタンス変数にアクセスすることになってしまう。
class Person(object): # クラス変数 count = 1 def __init__(self, age=8): # インスタンス変数 self.__age = age def add_count(self): # 参照は構わないが、ややこしい可能性あり print(self.count) # これをするとインスタンス変数になってしまう self.count += 1 # 以下のどれかにする Person.count += 1 # __class__.count += 1 # type(self).count += 1 print(self.count) print(Person.count) # クラスメソッド(clsでクラス変数にアクセス) @classmethod def get_cls_count(cls): return cls.count
これを避けるには以下のどれかの方法でクラス変数にアクセス(更新)する。
参照だけならselfでも問題ないが、可読性や取り違え防止を考えると参照時も統一したほうが良いかもしれない。
見た目のわかりやすさから言うと__class__がいいように思う。
Person.count += 1 __class__.count += 1 type(self).count += 1
クラスメソッドからはclsでアクセスする。
ちなみにclsは慣例であって別の名前でも問題ない。
そもそもインスタンスメソッドからクラス変数をアレコレ更新する、というのがそもそも設計として良くないとは思われるが、
使いたくなる場面は出てくるだろう。
ログインしていることを前提とした機能の場合、
強制的にログイン画面に飛ばしたい。
クラスベースではLoginRequiredMixinを実装することで可能となる。
ログイン後は、指定した画面に遷移する。
デフォルトではアクセスしようとした画面に戻してくれる。
from django.contrib.auth.mixins import LoginRequiredMixin class HomeView(LoginRequiredMixin, ListView):
このMixinは一番左に記述する必要がある。
遷移先はsettings.pyの下記で設定が可能。
ない場合はデフォルトが適用される。
LOGIN_URL = "accounts:login"
チェック関数を自作して条件を通過した場合にアクセスさせる
Formクラスにもバリデーションを定義することができるが、
Modelクラスにも定義することができる。
バリデーションを実施するにはfull_clean()を呼べばよい。
full_clean()では下記が呼ばれる。
clean_field() -> 各フィールドのvalidatorsに定義したものが呼ばれる
clean() -> フィールドに関連しない全体のチェック。cleanを定義していなければ何もしない。
validate_unique() -> フィールドに定義したunique制約をチェックする
validate_constraints() -> Meta.constraintsに定義したデータベース制約をチェックする
save()では呼ばれないのでその前で呼ぶ。
問題があった場合はValidationErrorをキャッチする。
"""インスタンスの保存処理""" try: sample = Sample() sample.full_clean() sample.save() except ValidationError as e: print(e) except DatabaseError as e: print(e)
"""モデルクラス""" def clean(self) -> None: """フィールドに関連づかないバリデーションエラー""" something_happen = True if something_happen: raise ValidationError("何らかのエラー!!")
save()で呼ぶにはオーバーライドする。
"""モデルクラス""" def save(self, force_insert, force_update, using, update_fields): """saveの前になにかさせる場合""" self.full_clean() return super().save(force_insert, force_update, using, update_fields)
そもそもFormクラスのis_valid()を呼ぶことでこいつが呼ばれる思想なのかもしれない。
Formのis_valid() -> full_clean() -> _post_clean() -> Modelのfull_clean()
この順番で呼ばれてくるようだ。
画面がいらない場合、テンプレートを使わない場合はクラスベースではViewを使用します。
HttpResponseを作ってcontentにセットして返せば良し。
他のメソッドが必要なら、def post, def headなどを定義すれば良し。
from django.views.generic import View class JsonTestView(View): """テンプレート使わない""" def get(self, request, *args, **kwargs) -> HttpResponse: response = HttpResponse() response.content = self.create_json() response.headers["Content-Type"] = "text/json" return response def create_json(self): data = { "id": 1, "name": "ジャック", "age": 25, } return json.dumps(data)
パターンは2つある
1.モデルオブジェクトに紐づける(SELECTの場合)
2.モデルに関係ないSQLを実行する(INSERT, UPDATE, DELETE, モデル生成しないSELECT)
detail = DailyReportDetail.objects.raw("SELECT * FROM reportapp_dailyreportdetail WHERE id = %s", [6])[0] detail.save()
結果はモデルオブジェクトになるので、モデルに合ったテーブルを指定している必要がある。
モデルを使うなら、主キーは必ずSELECTに含める(ないとエラー)
SELECTにないフィールドを参照したら、その時点で追加のクエリが発行される
INSERT, UPDATE, DELETEはこちら。
SELECTでモデルじゃなく単なる値を取りたい場合もこちら。
from django.db import connection with connection.cursor() as cursor: cursor.execute("UPDATE myapp_person SET flag = 1 WHERE last_name = %s", [name]) with connection.cursor() as cursor: cursor.execute("SELECT flag FROM myapp_person WHERE last_name = %s", [name]) row = cursor.fetchone() タプルで返される row = cursor.fetchall() 複数結果、タプルのリスト cursor.description タプルの1個目がフィールド名みたい -> [x[0] for x in cursor.description]
fetchone(), fetchall() はレコードをリストで返してくる。名前はつかない。
名前をつけたい場合はnamedtupleを使う。
descriptionを渡してフィールド名を定義し、レコード配列を渡す。
nt_res = namedtuple("Result", [x[0] for x in cursor.description]) res = nt_res(*row)
Djangoにはログイン画面を実装する方法が提供されていますので、
それを使用します。
Djangoの認証システムを使用する | Django ドキュメント | Django
プロジェクトルートのurls.py
urlpatterns = [ path("accounts/", include("django.contrib.auth.urls")),
accounts/login でアクセスできるようになります。
この一行で他にもlogout, password_changeなどが利用可能になります。
カスタマイズする場合はaccounts/loginなどそれぞれ定義します。
loginはテンプレートを自作する必要があります。
テンプレートはregistrationフォルダに入れる必要があります。
他の機能は下記のフォルダに入っている管理画面のテンプレートが使われるようです。
login.htmlはadminの方に入ってるので自作しないといけないです。
.venv/lib/python3.10/site-packages/django/contrib/admin/templates/registration
マニュアルにサンプルが載ってます。
コンテキストのリストにはないが画面内でuserが使える。
<h2>ログイン</h2> {% if form.errors %} <p>正しいユーザとパスワードを入れてください</p> {% endif %} {% if next %} {% if user.is_authenticated %} <p>このユーザー({{ user }})はページを見る権限がありません。別のユーザでログインしてください。</p> {% else %} <p>ページを見るにはログインしてください {{ user }}</p> {% endif %} {% endif %} <form action="{% url 'login' %}" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="login"> <input type="hidden" name="next" value="{{ next }}"> </form> <p><a href="{% url 'password_reset' %}">パスワード忘れた人</a></p>
settings.py
ログイン画面の場所、ログイン後に遷移する場所の設定。
LOGIN_URL = "login" LOGIN_REDIRECT_URL = "/admin/"