Djangoのメモ。 ====== Django ====== ===== 導入 ===== ラップトップでやったら簡単に同じ環境を作れた。すごい。 mkdir djangoApp python3 -m venv djangoApp # 仮想環境作成 cd djangoApp source bin/activate # 有効化 pip3 install django # 仮想環境にインストールされる ==== プロジェクト作成 ==== django-admin startproject djangoApp ==== サーバー起動 ==== manage.pyの配置されたディレクトリで、 python3 manage.py runserver localhost:8000にアクセスする。 ==== タイムスタンプ ==== from django.utils import timezone class Log(models.Model): regist_date = models.DateTimeField(default=timezone.now) from django.utils import timezone をインポートして default=timezone.now これでレコード登録時の日本時間が保存されます。 ==== 日付 ==== datetime → 書式化文字列 >>> import datetime >>> now = datetime.datetime.now() >>> now.strftime("%Y/%m/%d %H:%M:%S") '2012/01/01 20:29:39' ==== フィールドの初期値 ==== Class Post(models.Model): title = models.CharField(default='タイトル') ==== DBの初期化 ==== python manage.py flush ==== 初期設定 ==== python manage.py makemigrations django_test python manage.py migrate python manage.py createsuperuser ==== モデルのテンプレ ==== class Cooking(models.Model): id = models.AutoField(primary_key=True) register_time = models.DateTimeField(default=timezone.now) # 登録ボタンが押された時刻 cooking_time = models.DateTimeField() # 調理した時刻(フォーム入力) discard_time = models.DateTimeField(null=True, blank=True) # 廃棄ボタンが押された時刻 num = models.PositiveIntegerField() product = models.ForeignKey( 'Product', on_delete=models.CASCADE) ==== データに沿ったselectを出す方法 ==== 例えば商品テーブルに登録されているものすべてを名前フィールドで出して、idで値を調理テーブルに入れるようなときだ。 class FF_Form(ModelForm): class Meta: model = Cooking fields = ["product"] num = IntegerField() cooking_time = DateTimeField() などとする。 ポイントは、外部キーになっているフィールドを参照すること。 ここでは、商品テーブルではなく、調理テーブルのproductを参照する。 さらに、このままではobjectのコード?が出てきて何がなにやらわからないので、model.pyの class Job(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) job = models.CharField(max_length=64, blank=True) def __str__(self): return self.job def__str__を追加して、名前を返すようにすると、わかりやすくなる。 ==== 格納時の注意 ==== cooking = Cooking.objects.create( product_id=request.POST['product'], num=request.POST['num'], cooking_time=request.POST['cooking_time']) cooking.save() product_idに注目。POSTされる値はproductだが、格納されるのはproductになる。 これは、フォームがモデルからデータを取ってくるときに外部キーのフィールドがproductであるため。 モデルでは、外部キーでも_idがつかない。 ==== フォームの初期値の設定 ==== views.pyにて、 initial_value = { 'cooking_time': now } として、 form = ff_form(request.POST, initial=initial_value) とする。 ==== 自作フィルタの追加方法 ==== アプリケーション直下(models.pyとかあるところ)に、templatetagsディレクトリを作成する。 __init__.pyを作成し、test_tag.pyなどを作成し、中身を from django import template register = template.Library() @register.filter(name="multiplie") def multiplie(value, args): return value * args のようにする。あとはテンプレート内で、 {% load app_tag %} // 作成したファイル名を記述 {{ review.score | mulitiplie:20}} ==== 初期データ投入 ==== アプリケーション直下にfixturesディレクトリを作成する。 中にinitial.json(なんでもいい)を作成し、以下のように記述。 [ { "model": "django_test.Product", "pk": 1, "fields": { "title": "おはよう" } }, { "model": "app名.モデル名", "pk": 2, "fields": { "title": "こんにちは" } } ] そして、 python manage.py loaddata initial.json ==== time.time()でタイムゾーンが変わる問題 ==== datetimeではちゃんと表示できているのに、time()をするとタイムゾーンが変わってしまう。 djangoのテンプレートでは勝手に変換してくれるが、time()では変換がなくなる。 仕方ないので9時間足して対応した。 ==== editの例 ==== get・postによって処理を分ける。editとupdateは同じメソッドに書く。 def discard_post(request): if request.method == 'POST': cooking = get_object_or_404(Cooking, id=request.POST['id']) form = DiscardForm(request.POST) if form.is_valid(): cooking.discard_num = form.cleaned_data['discard_num'] cooking.save() return redirect(to='/ff_form') else: cooking = get_object_or_404(Cooking, id=request.GET['id']) form = DiscardForm({ 'discard_num': cooking.discard_num, 'id': cooking.id }) d = { 'form': form, } ==== 一部だけhiddenにする例 ==== class DiscardForm(ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['id'].widget = forms.HiddenInput() class Meta: model = Cooking fields = ['id'] discard_num = IntegerField(label='廃棄個数') id = CharField() ==== クエリ条件生成の例 ==== cookings = Cooking.objects.exclude(cooking_time__gt=today).filter(discard_num__exact=None) ==== ダミーカラムを非表示にする ==== dataTable.addRows([ /* 全カラム表示用。*/ {% for product in products %} [ '{{product.name}}', '', 'opacity: 0', new Date({{now | conv_dummytime | conv_graph}}), new Date({{now | conv_dummytime | conv_graph}}), ], {% endfor %} このようにすれば、非表示になる。線は見えないものの一応あって、時間が重なると2列になる。 ダミーを現在時にすると重なり、離れすぎるとグラフがおかしくなるので、12時間後にした。 ==== 現在時ライン ==== コピペで動作せず苦労したが、結局divのidをtimelineとして、packages名で揃えたことでできるようになった。よくわからない。 最初はコンテナ名がexample5.1,package名がtimelineだった。 これをどちらもtimelineにした。 コンテナとpackage名なので、たぶん指し示す位置が異なるのだろう。