Django Model のAnnotateが難しくて少し悩んだ

Viewで

result = SomeModel.objects.filter(p=p).values('key__id').annotate(sum=models.Sum('value'))

って感じでannotateでとあるキーに合致するレコードのサマリをとろうとしたのだが、resultはQuerySetだから

result[0]['sum']

なんてアクセスするとエラー(list index out of range)がでて、あー、だめなのかって思った。そこで

result.first()['sum']

ってやると、あー動いた動いたって安心してたんだけども、どうも合計が10.0あるレコードも集計されてなくて1.0とかになっておかしい。first()のせいで、1レコード分だけをSumしている挙動と思われる・・・。[0]自体はよくて、集計対象の行がないときに[0]はエラーになっているというだけなのだった。つまりこれでよかった。

if(result.count == 0):
    val = 0
else:
    val = resuilt[0].get('sum')

なんかコードがすっきりしないけど、これくらいなら1行で書く方法が何かありそう。
PHPだと $a = ( $i == “OK” ? True : False ) みたいなのができたけどpythonもあるのかな。

追記:調べてたら見つけた。

val = 0 if result.count == 0 else result[0].get('sum')

python django使うことにしたのはなぜかメモ

  • 正直CakePHP2でやりたいことは全部できるから別にいいと思っていたが、Viewもなにもかもarray( )だし$var[0][‘Item’][‘Attribute’]とかなんとかタイピング量がおおくて体力が削れる
  • RoRがまだ主流なことにおどろくものの今さら感がなあ。
  • laravelもいいけど、python触ってみたいな
  • 情報量一番多そうなやつ → django当確。
  • 結局Webアプリ開発って、やりたいことググって人のまねしまくって自分のほしいものを作るってだけなので。
  • Djangoはまあまあ使えるけどなんか痒いところにてが届かないなー、と思う。あとurlルーティングめんどくさい。CakePHP2が楽すぎただけ?

とか、勤務先の社食でごはん食べながらかいていたら、前に座った人がふところからラー油取り出してて、なんだこの人、ラー油常に持ってるのか。

DjangoでPaginateしたい

Djangoで何かを一覧で見るときにPaginateしたいのだが、例によって時間かけずに簡単にやりたい。

https://medium.com/@kjmczk/django-pagination-7c497995561e

こちらなど参考になったが、CSSがどこでどう設定したらきれいになるのかよくわからないのと、あとget_query_setとか、get_contextとか、この辺がやっぱりわかりにくい。一応なんかそれっぽく動いたけども、コードのメンテがめんどくさそうだ。なんかやろうとするたびに調べないといけなさそう。

結局Paginator的なSnippetはtemplatesに以下くらいを作って

{% if is_paginated %}
<p class="paginator">
    {% for num in paginator.page_range %}
    {% if page_obj.number == num %}
    <!-- <li class="page-item active"> -->
      <span class="this-page">{{ num }}</span>
    <!-- </li> -->
    {% else %}
    <!-- <li class="page-item"> -->
      <a class="page-link" href="?page={{ num }}">{{ num }}</a>
    <!-- </li> -->
    {% endif %}
    {% endfor %}
{% endif %}

Djangoの公式マニュアル見たら、GenericなListView使わずにこうやって書く方法が見つかった。

from django.core.paginator import Paginator
from django.shortcuts import render

from myapp.models import Contact

def listing(request):
    contact_list = Contact.objects.all()
    paginator = Paginator(contact_list, 25) # Show 25 contacts per page.

    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'list.html', {'page_obj': page_obj})

あとでこれで書き直そう。

Python Django: ModelFormの使い方頑張って調べて時間浪費するのもうやめる

DjangoのForm関連の機能は手間を色々減らしてくれる気がするので、ぜひ使い方をマスターして活用したいな、と思っていたけど、かゆいところに手が届かいので、一部あきらめる。

[app/form.py]
from django import forms
from .models import Project

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ["field1", "field2", "field3"]

これだけでFormオブジェクトそのものはできちゃうので、Viewに1行くらいコンテキストに渡す処理書いてあげるだけで、Template側では

        <form method="POST"> {% csrf_token %}
            <fieldset class="module aligned">
                {% for field in form %}
                <div class="form-row"><div>
                    <label>{{ field.label_tag }}</label>
                    <div class="related-widget-wrapper">
                        {{ field }}
                        {{ field.errors }}
                    </div>
                </div></div>
                {% endfor %}
                <input name="submit" type="submit" value="Regist" />
            </fieldset>
        </form>

これ書いてあげるだけでフォーム作ってくれちゃうし、こりゃ今後フィールド増えたときも便利だなあと確かに助かったんだけども、View側でPOSTを受け取ったときが困り物で

    if(request.method == 'POST'):
        form = ProjectForm(request.POST)
        if not form.is_valid():

これ、Formのフィールドからはあえて削ったフィールドについては、手で横からセットしてあげることが多分できないんじゃないだろうか。無理やりrequest.POSTの中身をいじってから処理するのもなんか違う。上記の例だとformのオブジェクトに対してなんかメソッドやらでsetすることはできないのかと調べたものの出てこないし、Validationなんかも怪しいところだ・・・。

色々考えたすえ、ModelFormは画面の生成と一定のValidationでは頼ってみることにするけど、データ編集してDBにレコード保存する処理はModelで直で書いてあげることにする。これはもうその方がわかりやすい。

したら、Viewはこんなことになった。ピエン。

    if(request.method == 'POST'):
        form = ProjectForm(request.POST)
        if not form.is_valid():
            ctx['form'] = form
        else:
            p = request.POST
            pj = Project(
                field1=p['field1'],
                field2=p['field2'],
                field3=p['field3'],
                field4=xxxxxxx,  # Formからではなく自分で別の方法で取得させる
                field5=xxxxxxx,  # Formからではなく自分で別の方法で取得させる
            )
            pj.save()
            messages.success(request, 'Success')
            return redirect('xxxx:xxxxx')

いいのかなこれ。ちゃんと動いて、あとからメンテできればいいっていうポリシーでやってるけど、不安だ。

Lubuntu: Atom Text Editorが急に起動しなくなる

Atomをデスクトップメニューから起動しようとしても、しばらくしたらダウンしてしまう症状。
試しにシェルから起動してみたらこんなログが出ておる。Linux版のAtomはなんかトラブルが多いな。

user@xxx:~ $ atom
user@xxx:~ $ /usr/bin/atom: line 195:  3122 Illegal instruction     (core dumped) nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$ATOM_HOME/nohup.out" 2>&1
(node:3190) Electron: Loading non-context-aware native module in renderer: '/usr/share/atom/resources/app.asar.unpacked/node_modules/superstring/build/Release/superstring.node'. This is deprecated, see https://github.com/electron/electron/issues/18397.
(node:3190) Electron: Loading non-context-aware native module in renderer: '/usr/share/atom/resources/app.asar.unpacked/node_modules/pathwatcher/build/Release/pathwatcher.node'. This is deprecated, see https://github.com/electron/electron/issues/18397.
[3122:0919/131037.889620:FATAL:gpu_data_manager_impl_private.cc(439)] GPU process isn't usable. Goodbye.

GPU processが使えないってなんだよ・・・とググって見たけど

https://forum.manjaro.org/t/error-gpu-process-isnt-usable-goodbye/104611

こちらを発見して、以下の太字のところだけ追加したらスッキリ解決。意味は不明だけど別にいいか。。。

$ sudo vim /usr/share/applications/atom.desktop

[Desktop Entry]
Name=Atom
Comment=A hackable text editor for the 21st Century.
GenericName=Text Editor
Exec=env ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT=false /usr/bin/atom %F --no-sandbox
Icon=atom
Type=Application
StartupNotify=true
Categories=GTK;Utility;TextEditor;Development;
MimeType=application/javascript;application/json;application/x-httpd-eruby;application/x-httpd-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/x-ruby;application/x-bash;application/x-csh;application/x-sh;application/x-zsh;application/x-shellscript;application/x-sql;application/x-tcl;application/xhtml+xml;application/xml;application/xml-dtd;application/xslt+xml;text/coffeescript;text/css;text/html;text/plain;text/xml;text/xml-dtd;text/x-bash;text/x-c++;text/x-c++hdr;text/x-c++src;text/x-c;text/x-chdr;text/x-csh;text/x-csrc;text/x-dsrc;text/x-diff;text/x-go;text/x-java;text/x-java-source;text/x-makefile;text/x-markdown;text/x-objc;text/x-perl;text/x-php;text/x-python;text/x-ruby;text/x-sh;text/x-zsh;text/yaml;inode/directory
StartupWMClass=atom
~                           

Lubuntu: あとからFcitx + Mozcで日本語入力環境を整える

インストール時点では英語環境にしたけど、あとから日本語入力環境を入れた。
Lubuntu 22.04。

sudo apt install fcitx-mozc

あと、意味があったかどうかわからないけど、この辺いくつか触って

こんな具合にして

それでも急には有効になってくれないので、Rebootしたら問題なく入力できるようになりました。