MPTT tree_id

MPTT Tree ID Django + mysql: transaction.atomic() で select_for_update() を使ってレコードをロックしたときのメモ MySQL で採番機能(シーケンス)を実装する方法を整理する MySQL のロックについて公式ドキュメントを読みながら動作検証してみた〜テーブルレベルロック〜 分散ロック Distributed Locking in Django 1 2 3 4 from django.core.cache import cache with cache.lock("somekey"): do_some_thing() redis-py: https://github.com/redis/redis-py/blob/d3a3ada03e080f39144807c9fbe44876c40e0548/redis/client.py#L394 デッドロック Hook available for automatic retry after deadlock in django and mysql setup 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import django.db.backends.utils from django.db import OperationalError import time original = django.db.backends.utils.CursorWrapper.execute def execute_wrapper(*args, **kwargs): attempts = 0 while attempts < 3: try: return original(*args, **kwargs) except OperationalError as e: code = e.args[0] if attempts == 2 or code != 1213: raise e attempts += 1 time.sleep(0.2) django.db.backends.utils.CursorWrapper.execute = execute_wrapper

2023年11月6日 · 1 分

Redis キーの作成時刻

Redis キーの登録日時 Redis でキーを登録した時刻を取得するには、残念ながら直接的な方法はありません。Redis はキーの作成日時や更新日時を保存していないからです ¹。ただし、いくつかの回避策があります。 キーを登録するときに、別のキーにタイムスタンプを保存する。 例えば、SET foo barとするときに、SET foo:timestamp 1636106362というように、キーの名前に:timestampを付けて現在の UNIX 時間を値として保存する。 この方法では、キーの数が増えるとメモリの消費量も増えることに注意が必要です。 キーの値にタイムスタンプを含める。 例えば、SET foo bar:1636106362というように、値の末尾に:と現在の UNIX 時間を付ける。 この方法では、値の取得や操作において、タイムスタンプを除去する必要があることに注意が必要です。 キーに有効期限を設定する。 例えば、EXPIRE foo 3600とすると、キーfooは 1 時間後に削除される。 このとき、TTL fooとすると、キーの残りの有効期限が秒単位で返される。 この値から、キーの登録時刻を逆算することができる。この方法では、キーが削除されると時刻を取得できなくなることに注意が必要です。 以上の方法のいずれも完璧ではありませんが、Redis でキーの登録時刻を取得するための可能な解決策として参考にしてください。 ¹: Redis でキーの作成日時や更新日時を取得する方法はありますか? - スタック・オーバーフロー. ソース: Bing との会話 2023/11/6 (1) redis-cli でよく使うコマンド 20 選 #Redis - Qiita. https://qiita.com/hatsu/items/a52817364160e0b6bb60. (2) redis-cli でよく使うコマンド 20 選 #Redis - Qiita. https://qiita.com/hatsu/items/a52817364160e0b6bb60. (3) 全データ型対応の操作 — redis 2.0.3 documentation - shibu.jp. http://redis.shibu.jp/commandreference/alldata.html. (4) 【2022 年最新版】【Redis メモ・3】キーに有効期限を付与し …. https://www.servernote.net/article.cgi?id=redis-note-3. (5) セッション管理として Redis を使用する - RAKUS Developers Blog …. https://tech-blog.rakus.co.jp/entry/2017/10/17/111828. (6) ja.wikipedia.org. https://ja.wikipedia.org/wiki/Redis.

2023年11月6日 · 1 分

RDS バーストバランス

RDS バーストバランス バーストバランス https://qiita.com/s-katsumata/items/b12f943905ff68474e38 IOPS https://qiita.com/mk34/items/28ccb7a3e84964d79203 ストレージサイズを増やす ストレージの自動スケーリング クレジットバランス https://dev.classmethod.jp/articles/rds_gp2_iocreditbarance/ スロークエリ https://qiita.com/satofujino/items/a7350aefc3cdde563592

2023年11月1日 · 1 分

utf8 -> cp932

UTF8 -> CP932 【pandas】csv 出力時に cp932 を指定すると UnicodeError が起こる場合の対処法 [Python3] Shift_JIS と UTF-8 と ASCII を行き来する コーデック: エラーハンドラ UTF-8 → cp932(Shift_JIS)変換表

2023年10月11日 · 1 分

MySQL: 𠮷(つちよし)

MySQL: 𠮷(つちよし) データベース/テーブル utf8mb4にすること 1 ALTER TABLE customers_customer CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 確認: $ echo "show variables like 'character%';" | python manage.py dbshell Variable_name Value character_set_client utf8mb4 character_set_connection utf8mb4 character_set_database utf8mb4 character_set_filesystem binary character_set_results utf8mb4 character_set_server utf8mb4 character_set_system utf8mb3 character_sets_dir /rdsdbbin/mysql-8.0.28.R4/share/charsets/ character_set_system utf8mb3 が問題 接続 を utf8mb4 にすること django: OPTIONS/charset=utf8mb4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 In [1]: from django.conf import settings In [2]: settings.DATABASES Out[2]: {'default': {'ENGINE': 'django.db.backends.mysql', 'HOST': 'prod-db-instance.xxxxxxxx.ap-northeast-1.rds.amazonaws.com', 'NAME': 'coresys_masters', 'USER': 'coresys_masters', 'PASSWORD': 'va0Gaighoo3Paez8', 'OPTIONS': {'charset': 'utf8mb4', 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'TIME_ZONE': None, 'PORT': '', 'TEST': {'CHARSET': None, 'COLLATION': None, 'MIGRATE': True, 'MIRROR': None, 'NAME': None}}}

2023年10月1日 · 1 分

AWS:ECS: スケジュールタスク

AWS: ECS: スケジュールタスク CloudTail FailedInvocations が記録されて ECS タスクが起動しないときの対処方法

2023年9月29日 · 1 分

RDS MySQL 接続確認

接続先のインスタンスを識別する方法 (EC2 / RDS MySQL) https://qiita.com/hirooka622/items/d9ffb3aaf5fbba0a8a8d 1 2 3 4 5 6 7 8 9 mysql> show variables like "hostname"; +---------------+---------------+ | Variable_name | Value | +---------------+---------------+ | hostname | ip-172-23-1-5 | +---------------+---------------+ 1 row in set (0.00 sec)

2023年9月3日 · 1 分

DRF: DataFrame を使って CSV エクスポート

DRF: DataFrame を使って CSV エクスポート CSV レンダラー 1 2 3 4 5 6 7 def dataframe_to_csv_stream(df, encoding=None, **kwargs): buffer = BytesIO() df.to_csv(buffer, **kwargs) buffer.seek(0) if encoding: return BytesIO(buffer.read().decode("utf8").encode(encoding)) return buffer 1 2 3 4 5 6 7 8 9 10 class DataFrameCSVRenderer(BaseRenderer): media_type = "text/csv" format = "csv" def render(self, data, media_type=None, renderer_context=None, writer_opts=None): renderer_context = renderer_context or {} if not isinstance(data, pd.DataFrame): data = pd.DataFrame(data) stream = dataframe_to_csv_stream(data, index=False) return stream.read().decode("utf-8-sig") DataFrame を返すリストシリアライザ 1 2 3 4 5 6 7 class DataFrameSerializer(serializers.ListSerializer): @property def data(self): ret = super().data ser = ret.serializer.child columns = dict((name, field.label) for name, field in ser.fields.items()) return pd.DataFrame(ret).rename(columns=columns) エクスポートするシリアライザを生成するメタクラス 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class ExpporSerializerMetaclass(serializers.SerializerMetaclass): EXPORT_META = {} FIELD_CLASS_DEFAULTS = {} @classmethod def create_fields(cls): def _create_field(item): label, name, klass = item defaults = cls.FIELD_CLASS_DEFAULTS[klass] return (name, getattr(serializers, klass)(label=label, **defaults)) return dict(map(_create_field, cls.EXPORT_META)) @classmethod def annotate(cls, queryset): raise NotImplementedError() def __new__(cls, name, bases, attrs, **kwargs): attrs["Meta"].fields = [i[1] for i in cls.EXPORT_META] # CSVで返答するカラム attrs["Meta"].list_serializer_class = DataFrameSerializer # リストシリアライザ attrs.update(**cls.create_fields()) attrs["annotate"] = cls.annotate # クエリセットをアノテートさせるクラスメソッド return super().__new__(cls, name, bases, attrs, **kwargs) 実際のメタクラス 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class IncomeExpporSerializerMetaclass(ExpporSerializerMetaclass): # (ラベル, フィールド名, フィールドクラス名) EXPORT_META = [ ("会社コード", "order__company_code", "CharField"), .... ] # フィールドクラスのデフォルト値 FIELD_CLASS_DEFAULTS = dict( CharField=dict(read_only=True), DecimalField=dict(max_digits=12, decimal_places=1, read_only=True), ) @classmethod def annotate(cls, queryset): """ クエリセットを適切にアノテートする""" def _ann(item): label, name, klass = item if name.startswith("order__"): # リレーション return (name, F(name)) if name.startswith("meme__"): # 固定値 return (name, Value("")) # その他はモデルフィールドなのでアノテートしない return (None, None) ann = dict(filter(lambda i: i[1] is not None, map(_ann, cls.EXPORT_META))) return queryset.annotate(**ann) 実際のシリアライザ 1 2 3 class IncomeExportSerializer(serializers.ModelSerializer, metaclass=IncomeExpporSerializerMetaclass): class Meta: model = models.Income API 本体(ビューセット) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class IncomeViewSet(VS.BaseModelViewSet): serializer_class = serializers.IncomeSerializer queryset = models.Income.objects.all() pagination_class = paginations.Pagination renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (DataFrameCSVRenderer,) def get_serializer_class(self): """ export アクションでシリアライザを切り替える """ res = { "export": serializers.IncomeExportSerializer, }.get(self.action, super().get_serializer_class()) return res def get_queryset(self): """ export アクションの場合、必要なアノテーションを行う """ qs = super().get_queryset() if self.action == "export": qs = serializers.IncomeExportSerializer.annotate(qs).filter(level=0) return qs return qs @decorators.action(methods=["get"], detail=False) def export(self, request, pk=None): ## リスト処理を行うと シリアライザとレンダラで勝手にCSVを返答する(Accept: text/csvの時) return self.list(request)

2023年8月22日 · 2 分

pandas SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.

pandas : SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. どちらでも Warning: 1 2 3 4 5 6 def _balance(df): if df["bookitem_kind"] == "1": return -1 * df["amount"] return df["amount"] df_epm_cost["amount2"] = df_epm_cost.apply(_balance, axis=1) 1 df_epm_cost["amount"].where(df_epm_cost["bookitem_kind"] == "0", -1 * df_epm_cost["amount"], inplace=True) ValueError: cannot reindex on an axis with duplicate labels 1 df_epm_cost.loc[df_epm_cost["bookitem_kind"] == "1", "amount2"] = df_epm_cost["amount"] * (-1) FutureWarning: reindexing with a non-unique Index is deprecated and will raise in a future version ValueError: cannot reindex on an axis with duplicate labels インデックスを削除するとうまく行く: ...

2023年8月20日 · 1 分

Django 動的モデル生成

Django : 動的モデル生成 定義されたメタ情報で同じテーブルを複数作る 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 from pathlib import Path import pandas as pd from django.conf import settings from django.db import connection, models def get_meta(name): """ 定義情報(CSV)ファイル """ path = META_DIR / f"{name}.map.csv" return pd.read_csv(path, dtype="str").fillna("").to_dict(orient="records") def named_model(name, code): meta = get_meta(name) class_name = f"{name}{code}" table_name = f"{name}_{code}" unique_fields = list(map(lambda i: i["column"], filter(lambda i: i["unique"] == "1", meta))) class Meta: db_table = f"oracle_{table_name}" constraints = [ models.UniqueConstraint( fields=unique_fields, name=f"uniq_{table_name}", ), ] def _field(item): params = {"db_index": True} if item["db_index"] else {} params["blank"] = True return ( item["column"], models.CharField(verbose_name=item["label"], max_length=100, null=True, default=None, **params), ) fields = dict(map(_field, meta)) attrs = {"__module__": "oracle.models", "Meta": Meta, **fields} models_class = type(class_name, (models.Model,), attrs) return models_class def get_named_model(name, code): # モデルクラス取得 model_class = named_model(name, code) if model_class._meta.db_table in connection.introspection.table_names(): # テーブルが存在していたら終了 return model_class # テーブルの作成 with connection.schema_editor() as schema_editor: schema_editor.create_model(model_class) return model_class

2023年8月16日 · 1 分