diadia

興味があることをやってみる。自分のメモを残しておきます。

SQL 操作する行の絞り込みで使うINとANYの差異

参考:https://docs.oracle.com/cd/E16662_01/doc/timesten.1121/b56051/ttsql268.htm

INとANYの使い分け

INは値が一致しているかどうかを真偽で判定するものである。

 WHERE 値 IN (値1, 値2, 値3, 値4, 値5)

ANYは値を比較演算子を用いて真偽を判定する。つまり比較演算子を伴うところが異なる。

 WHERE 値 > ANY(値1, 値2, 値3, 値4, 値5)

SQL 各種JOINについて

JOINの種類

JOINはテーブルの結合を行うもので、JOIN, INNER JOIN, OUTER LEFT JOIN, LEFT JOIN, RIGHT JOIN, OUTER RIGHT JOIN, FULL JOINなどの種類がある。

それでこれらを使い分ける必要があるわけだけれど、使い分けとしてJOIN, LEFT JOIN, RIGHT JOINの3種類で使い分けることができる。

JOINは別名INNER JOINである。LEFT JOINは別名OUTER LEFT JOINであり、RIGHT JOINはOUTER RIGHT JOINである。LEFT JOINとRIGHT JOINはOUTER JOINと呼ばれるタイプのJOINである。これに対応するのが先程説明したINNER JOINである。

INNER JOINとOUTER JOINの働き

INNER JOINは結合対象のテーブルに結合すべき行が見つからない場合に行が消滅してしまう結合である。したがって結合もとと結合対象の両方が存在しているときに限り行がゆうこうとなる。一方OUTER JOINは本来表から消滅してしまう行も強制的に出力する結合である。

詳しくはスッキリわかるSQL入門第2版を読むと良い。また以下もおそらく同じことを説明している。
https://qiita.com/ngron/items/db4947fb0551f21321c0

SQLの学習

参考書:
スッキリわかるSQL入門第2版
SQL ゼロから始めるデータベース操作

SQLの命令分類

  • DML(Data MAnipulation Language)
    • SELECT
    • INSERT
    • UPDATE
    • DELETE
    • EXPLAIN
    • LOCK TABLE
  • DDL(Data Definition Language)
    • CREATE
    • ALTER
    • DROP
    • TRUNCATE
  • TCL(Transaction Control Language)
    • COMMIT
    • ROLLBACK
    • SET TRANSACTION
    • SAVEPOINT
  • DCL(Data Control Language)
    • GRANT
    • REVOKE

 

メモ

INSERT文で具体的な値を入れないと、NULLがデータベースに入力される。NULLではない値を入力したい場合にはCREATE TABLEでdefaultを設定すれば良い。

WHERE句でIS NULL, IS NOT NULLを使う。WHERE句ではLIKE演算子やBETWEEN演算子もある。IN, NOT IN演算子もある。

主キーとなるカラムが持つべき特性
必ず何らかのデータが格納される(NULLではない)。
値が他の行と重複しない。

操作する行の絞り込み

行の絞り込みでIS NULLやIS NOT NULLを使うのでWHERE句で使うと仮定しておく。

検索結果を加工

  • DISTINCT
  • ORDER BY
  • OFFSET/FETCH
  • UNION
  • EXCEPT
  • INTERSECT

式と関数

 

関数

  • 文字列に係る関数
    • LENGTH
    • TRIM
    • REPLACE
    • SUBSTRING
    • CONCAT
  • 数値に係る関数
    • ROUND(四捨五入)
    • TRUNC(四捨五入の切り捨て)
    • POWER(べき乗を計算する)
  • 日付に係る関数
    • CURRENT_DATE(現在の日付を得る関数)
    • CURRENT_TIME(現在の時刻を得る関数)
  • 変換に係る関数
    • CAST(データ型を変換する)
    • COALESCE(最初に登場するNULLでない値を返す)
関数の補足

SUBSTRINGについて

SUBSTRINGは文字列からある位置から定められた文字数を抽出する関数である。pythnで言えば文字列のスライスであり、mojiretsu[5:8]みたいなことを実現する関数である。使い方は以下のように、

SUBSTRING(カラム名, 文字列抽出の開始位置, 開始位置から文字列取得数)

SUBSTRING(文字列, 6, 4)

疑問がある。プログラミング言語の場合文字列の開始時点は0から始まるけどSQLの場合は1から始まるのか?また-1とすることもできないのか?

 

TRIMについて

TRIMは文字列の空白に対して作用するものだけれども、それは文字列の始まる前、または終わりにある空白に対して作用する。したがって文字列中の空白を削除したい場合には、REPLACE関数を使うことになる。

 

集計とグループ化

集計の関数は以下の通り。集計の関数はSELECT文でしか利用できない。さらに言えば、SELECT文の選択列リストか、ORDER BY句、HAVING句のみ記述することができる。

  • SUM
  • MAX
  • MIN
  • AVG
  • COUNT

集計関数を使うと集計結果として一行に集約される。例えば項目別にSUMやMAXの結果を得たいという動機にたいしてグループ化で対応できる。あるカラムの項目別に集計関数を適用する方法だ。これはGROUP BY句を使えば実現できる。また集計結果に対し、フィルタリングしたい場合もある。それに対してはWHERE句と非常に似たHAVING句 を用いれば良い。両者の違いは集計関数が実行されるタイミングが異なるだけである。

テーブルを分割することについて

テーブルを分割すると、データを安全、確実、高速に取り扱うことができる。これはつまり、データの管理に適することを意味する。しかしながらテーブルを分割すると、データの一覧性が損なわれ理解しづらいデメリットがある。このデメリットを克服する技術がjoinである。

トランザクション

DBMSによるトランザクション制御とは具体的に、

を意味する。

DBMSにはトランザクションの制御を行うために、内部でロック(lock)と呼ばれる仕組みがある。ロックっていう仕組みは、あるトランザクションが現在読み書きしている行に鍵をかけ、他の人のトランザクションからは読み書きできなくする仕組み。このロックはトランザクションがコミットやロールバックで終了されると解除される。そして他人がロックしている間は、他人のトランザクションが終了するまでは自分は待たされる。通常このロックの待ち時間は通常数ミリ秒以下らしい。pythonのsqlite3を使って複数のスクリプトを同時に走らせると、lockと書かれたエラーが出るのはこれが原因なのだろう。

分離レベル

DBMSにはどの程度厳密にトランザクションを分離するかをトランザクション分離レベルとして指定することができる。これは各DBMSで固有のレベルが定まっているという意味ではなく、ユーザが分離レベルを指定することができるという意味である。多くのDBMSではデフォルトでREAD COMMITTEDになっている。他の分離レベルに設定するには、
SET TRANSACTION ISOLATION LEVEL 分離レベル を使って変更することができるようだ。

GRANT文とREVOKE文

DCLは、誰に、どのようなデータ操作やテーブル操作を許す家といった権限を設定するSQLの総称。権限を付与するGRANTと権限をなくすREVOKEが存在する。

GRANT 権限名 TO ユーザ名
REVOKE 権限名 FROM ユーザ名

PostgreSQLのエンコーディングについて

エンコーディングについてのドキュメント

djangoでpostgeSQLを使う時ALTER ROLE username SET client_encoding TO 'UTF8';とやってきた。これはデータベースのエンコーディングUTF-8に変えることだと思っていた。しかし違う可能性が発覚。
ベストアンサー参照すること
http://q.hatena.ne.jp/1348030529
ということでドキュメントを見てみる。
https://www.postgresql.jp/document/11/html/multibyte.html

データベースのエンコーディング設定

データベースのエンコーディングの設定場面は二か所あるようだ。一回目がデフォルトのエンコーディングを定めるもの。二回目が個別具体的に定める。デフォルトのエンコーディングはinitdbコマンドを入力してデータベースクラスタを初期化するときに定められる。これはデフォルト値になるのでデータベースを作成するときにデフォルト値を上書きすることができる。

initdb -E EUC_JP

上記のようにデフォルトの設定する。

データベースを作成時には以下のように行う

createdb -E EUC_KR -T template0 --lc-collate=ko_KR.euckr --lc-ctype=ko_KR.euckr korean
#または
CREATE DATABASE korean WITH ENCODING 'EUC_KR' LC_COLLATE='ko_KR.euckr' LC_CTYPE='ko_KR.euckr' TEMPLATE=template0;

postgresqlクライアント側の文字セット設定

クライアント側の文字設定は以下のように行う。いろいろな方法で設定できる。

\encoding SJIS

SET CLIENT_ENCODING TO 'value';

自動文字セット変換は、どうやらクライアント側で入力したSQLをデータベース側で適切なエンコードになおしてデータベースに反映させる仕組みらしい。サーバのエンコードに対して対応していないエンコード方法をクライアント側で設定するとエラーが出てくるようだ。おそらくこの機能を通じてクライアントとサーバのエンコード変換の質を担保する、ということではないだろうか。

PostGISについて

GISとは

GISは地理情報システム(GIS:Geographic Information System)のことである。
https://www.gsi.go.jp/GIS/whatisgis.html

PostGISインストール方法

参考になるものは以下になる。
https://qiita.com/chanmaru/items/0cb67455c294943ae649
https://lets.postgresql.jp/documents/tutorial/PostGIS/1

インストール方法

windowsではpostgresqlインストーラの実行が完了し、最後に"スタッグビルダを起動しますか?"と聞かれるので、そこでスタッグビルダを使うと追加でいろいろなものをダウンロード、インストールすることができるようだ。postgresqlwindowsに入れる際はデータを格納するdataディレクトリをデフォルトの場所に設置しないようにしたい。そのためにインストーラの実行中に、ディレクトリを任意のところに指定する。なぜならC:\Program Files 配下のファイルは Windowsの保護対象であるため、設定ファイルの編集が面倒になってしまうから。補足するとスタッグビルダは別途起動することもできる。
参考:https://lets.postgresql.jp/documents/tutorial/windows/

PostGISについてはスタッグビルダを起動してインストールする。

CentOS7におけるPostGISのインストールは分かり次第更新したい。

上記はインストーラを使う場合のやり方である。ソースコードからインストールする方法もある。これはconfigure,make,make installのようなものが関係してくる。
https://qiita.com/chihiro/items/f270744d7e09c58a50a5
configureスクリプト:https://en.wikipedia.org/wiki/Configure_script

 

f:id:torajirousan:20190810191535p:plain

windowsにおいてPostGISをインストールする場合

 

 

空間データベースの作成

参考:https://lets.postgresql.jp/documents/tutorial/PostGIS/2
空間データベース=Postgresql+PostGISに必要な関数やデータ型、デーブル

空間データベースとは、PostGIS に必要な関数やデータ型、テーブルなどがあらかじめ備わっているデータベースです。それ以外は特に通常のデータベースとは変わりありません。

作成方法

テンプレートが存在している場合と存在していない場合に分けられる。

テンプレートが存在している場合
$ createdb -T template_postgis (データベース名)
テンプレートが存在していない場合

テンプレートが存在していない場合には、データベースを作成して、PL/pgSQL を入れ、PostGIS 特有の関数、型、テーブル等を手動で作成する必要があります。

createdb (データベース名) -E UTF-8
$ createlang plpgsql (データベース名)
$ psql (データベース名) -f $(postgis_contrib)/postgis.sql
$ psql (データベース名) -f $(postgis_contrib)/spatial_ref_sys.sql

PostGIS データの格納

参考:https://lets.postgresql.jp/documents/tutorial/PostGIS/3

PostGISが受け付けるデータファイルの形式は、シェープファイルという形式らしい。ただしこれは単一のファイルではなく複数のファイルが有機的に一体として機能するもので、ファイルをまとめてシェープファイルと呼ぶようだ。シェープはshapeを指す。
3つのファイルで構成される。拡張子はそれぞれshp,dbf,shxである。
参考:https://www.pasco.co.jp/recommend/word/word028/

コマンドラインshp2pgsqlはシェープファイルからSQLに変換する。

python 組み合わせを作る

与えられた数字から組み合わせを作る

任意の数が与えられてそこからすべての組み合わせを作る場合どうすればよいのか。
標準ライブラリを使うとかんたんに処理できるようだ。

from itertools import combinations

number_list = [1,2,3,4,5,6,7,8]
list(combinations(number_list, 2))

こうすると2つの組み合わせができる。3にすれば3つの組み合わせになる。全ての組み合わせをする場合は以下のように行う。

from itertools import combinations

number_list = [1,2,3,4,5,6,7,8]

lst = []
for n in range(1,len(n)+1):
    l = list(combinations(number_list, n))
    for combi in l:
        lst.append(combi)

python dictから最大値関連の情報を取り出す

何らかの状況で連続した入力に応じてその数をカウントする必要があるとする。このカウントは辞書型データにするとデータの取り扱いが楽になると思われる。問題は辞書型データから最大値や最小値の関連情報をいかにして取得するか。

例えば100人の血液型データが順々に入力される。

 

O
A
B
O
O
...
A

 

その場合以下の感じで辞書型データを作ればよい。

# 血液型データの入力
blood = {}
for n in list(range(0,100):
    data = input()
    blood.setdefault(str(data), 0)

 

最大値関連情報の取り出し

辞書型データの値において最大値、最小値を取り出すのは、max()関数やmin()関数を使うことで取り出すことができる。<br/ > max関数やmin関数は引数がシーケンスなので値のリストデータを作成する必要がある。また以下のようにすれば、max値,min値のキーを取得することもできる。

# 多い血液型の出力、その人数を出力
max_number = max([v for v in blood.values() ])
print("血液型人数", max_number)

keys = [k for k,v in blood.items() if int(v) == max_number ]
for key in keys :
    print("血液型")
    print(key)
    

 

辞書の値のソート

値のソートは値のリストを作成し、soreted()関数に値のリストを引数として渡すと昇順のリストを戻り値として取得できる。
キーを値に応じて昇順に直す場合には以下のようにすれば良い。

value_list = [1,2,3,4,5,6,7] #昇順にして準備 
key_list = list()

for n in range(0, len(value_list)):
    for k,v in dict_data.items():
        if v == value_list[n]:
            key_list.append(k)
        else:
            continue

上記の状況は値がすべて一つずつを想定している。
値が重複する場合には以下のようにする。

value_list = [1,2,3,3,3,4,5,6,7] #昇順にして準備 
key_list = list()

for n in range(0, len(value_list)):
    for k,v in dict_data.items():
        if v == value_list[n] and k not in key_list:
            key_list.append(k)
        else:
            continue

データの一般化

プログラミングの基礎を最近読んでいます。OCamlを使ってプログラミングの考え方を学ぶっていうのがこの本のコンセプトです。
https://www.amazon.co.jp/dp/4781911609/

データの一般化

本書120ページあたりから。概要は関数を作っていると似たような関数ができてくる。これらの関数を一般化することでより多くの場面で使うことができるようになる。したがって一般化は大事みたいな内容。

学んだことをpythonで表現

多数決の意見のデータが以下の辞書型データとして存在している。
{"name":"satou", "iken":"yes"}
この辞書型データを格納したリスト型データをopinion_listとする。

opinion_list = [
    {"name":"satou", "iken":"yes"},
    {"name":"yasuda","iken":"no"},
    {"name":"takano","iken":"yes"},
    {"name":"ono",   "iken":"yes"},
]

このリストデータを読み込んで意見が"yes"の人数をカウントするとともに、別の関数として"no"のものも定義してみる。

def count_yes(lst):
    n = 0
    for ele in lst:
        if ele["iken"] == "yes":
            n += 1
        else:
            continue
    print("{}{}{}".format("yes","の人数は",n))
    
    
count_yes(opinion_list)
yesの人数は3

noのものは以下の通り。

def count_no(lst):
    n = 0
    for ele in lst:
        if ele["iken"] == "no":
            n += 1
        else:
            continue
    print("{}{}{}".format("no","の人数は",n))


count_no(opinion_list)
noの人数は1

次に両者を一般化して引数にyes,noを加えることで同じ結果を出力する関数countを設ける。また引数を"yes"として実行結果を確認する。

def count(lst,iken):
    n = 0
    for ele in lst:
        if ele["iken"] == iken:
            n += 1
        else:
            continue
    print("{}{}{}".format(iken,"の人数は",n))



count(opinion_list, "yes")
yesの人数は3

これで引数を変えることでカウントできる関数を作ることができた。しかしながら今までcount_yesをスクリプト上に書いてきた場合、修正が面倒になる。これについても解決できることが判明。それは一般化した関数countを使って再度count_yesを定義しなおすことである。

def count_yes(lst):
    count(lst,"yes")
    
    
count_yes(opinion_list)

結果はもちろん同じになる。

yesの人数は3

一般化した関数を使った場合使わない場合のコードの比較

使わない場合のコード

opinion_list = [
    {"name":"satou", "iken":"yes"},
    {"name":"yasuda","iken":"no"},
    {"name":"takano","iken":"yes"},
    {"name":"ono",   "iken":"yes"},

]

def count_yes(lst):
    n = 0
    for ele in lst:
        if ele["iken"] == "yes":
            n += 1
        else:
            continue
    print("{}{}{}".format("yes","の人数は",n))

    
def count_no(lst):
    n = 0
    for ele in lst:
        if ele["iken"] == "no":
            n += 1
        else:
            continue
    print("{}{}{}".format("no","の人数は",n))

いままでこの書き方をしていた。この書き方しか知らなかった。

一般化した関数を使わう場合のコード

opinion_list = [
    {"name":"satou", "iken":"yes"},
    {"name":"yasuda","iken":"no"},
    {"name":"takano","iken":"yes"},
    {"name":"ono",   "iken":"yes"},

]

def count(lst,iken):
    n = 0
    for ele in lst:
        if ele["iken"] == iken:
            n += 1
        else:
            continue
    print("{}{}{}".format(iken,"の人数は",n))
    

def count_yes(lst):
    count(lst,"yes")
    
def count_no(lst):
    count(lst,"no")

コードをかなりすっきり書くことができた。

再考:DetailViewの構造

DetailViewで詳細ページが表示できる理由

class ProductDetailView(DetailView):
    model = Product

上記の記述だけでhttprequestのGETが成立してしまうことをまず整理したい。

まずDetailViewはViewクラスを継承したものである。だからViewをカスタムしたものがDetailViewであり、GETのリクエストに対しViewのような流れでDetailViewも処理されると考えられる。そこでViewではどのようにGETのリクエストを返すか見てみる。

class ProductView(View):
    def get(self, request, *args, **kwargs):
        pk = self.kwargs["pk"]
        object = Product.objects.get(id=pk)
        context = {}
        context["object"] = object
        
        return render(request, "products/detail.html", context)

ProductDetailViewをProductViewと比べると、以下の違いがある。

  • objectを指定しないでもobjectが自動的に取得される。
  • 取得したobjectがcontextに自動で登録されている。
  • 自動的にオブジェクトをテンプレートにレンダリングされる。

細かく見ればさらに出てくるだろうが、まずこの3つが大きな違いだろう。
これらの違いはいかにして実現されているか、よく観察してみたい。

objectを指定しないでもobjectが取得される

これはDetailViewのget_object()メソッドが実行されると、自動的に特定のオブジェクトを取得することになっている。
https://github.com/django/django/blob/2.1/django/views/generic/detail.py#L20

def get_object(self, queryset=None):
    if queryset is None:
        queryset = self.get_queryset()

    pk = self.kwargs.get(self.pk_url_kwarg)
    slug = self.kwargs.get(self.slug_url_kwarg)
    if pk is not None:
        queryset = queryset.filter(pk=pk)
    ...
    try:
        # Get the single item from the filtered queryset
        obj = queryset.get()
    except queryset.model.DoesNotExist:
    ...
    return obj

DetailViewはget_objectメソッドを持つSingleObjectMixinを継承しているので、上記の機能を有する。話がそれるが、obj = queryset.get()はgetの引数がない。これについては下記の豆知識に詳細を書いておいた。

取得したobjectがcontextに自動で登録されている

これはBaseDetailViewのgetメソッドを見れば自動的に登録されていることが分かる。

BaseDetailView(SingleObjectMixin, View)のgetメソッド

def get(self, request, *args, **kwargs):
    self.object = self.get_object()      # 上記で説明したget_objectメソッドの実行
    context = self.get_context_data(object=self.object) # contextにobjectをぶち込んでいる
    return self.render_to_response(context)
    

ソース:https://github.com/django/django/blob/2.1/django/views/generic/detail.py#L105

そもそもユーザが任意のURLをリクエストすると、URLconf(=urls.py)でas_viewメソッドが実行される。as_viewメソッドはdispatchメソッドを呼び出す。そしてdispatchメソッドはhandlerという形式でViewまたはDetailViewのgetやpostメソッドを呼び起こす。この時にViewクラスはgetメソッドが存在していないので結果的にデベロッパーがgetメソッドを作らされるのである。それは先のないプラレールの線路の行き先を作るが如く...。一方DetailViewはgetメソッドが準備してあるのでデベロッパーが作る必要がない。この辺の背景を理解していると良いと思う。

自動的にオブジェクトをテンプレートにレンダリングされる

 render()関数はレンダリングしたHttpResponseオブジェクトを返す。
https://docs.djangoproject.com/ja/2.2/intro/tutorial03/#a-shortcut-render
render_to_responseメソッドはresponse_classを呼び出す。response_classはデフォルトではTemplateResponseオブジェクトを作成する。このオブジェクトはHttpResponse同じ場面で使うことができる(TemplateResponse ≒ HttpResponse)
この辺をもうちょっと資料を集めておきます。
https://docs.djangoproject.com/ja/2.2/ref/template-response/#using-templateresponse-and-simpletemplateresponse

豆知識

querysetからオブジェクトを取り出すとき、get()を使うが引数は必ずしも必要ない。通常はquerysetにオブジェクトが複数存在している時queryset.get(id=pk)みたいに記述する。しかしquerysetにオブジェクトが一個しか入っていない場合は例外として引数不要でget()を使うことができる。これは、ソースコードで使われている。
https://github.com/django/django/blob/2.1/django/views/generic/detail.py#L52

If you expect a queryset to return one row, you can use get() without any arguments to return the object for that row:

ドキュメント:https://docs.djangoproject.com/ja/2.2/ref/models/querysets/#django.db.models.query.QuerySet.get

toLocalStringメソッド

ベース

Javascriptメモ

本題

toLocalStringメソッド

対象オブジェクトを文字列化する。文字列化するのには他にtoStringメソッドもあるらしい。 これらの違いは、現在のロケールに応じた文字列表現を返しますかどうか。JSとUSだと文字列表現が異なる場合もありえるってこと。 pythonでは関数str()にあたるものが、toString、toLocalStringと整理して頭に入れておく。

メソッドの小文字と大文字に使い分ける規則はあるのか?

メソッドに前置詞にあたるものは小文字始まりになるという仮説を立てる。

Dateオブジェクト

DateオブジェクトにもtoLacaleStringメソッドがあった。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString

配列

ベース記事

Javascriptメモ

種類

疑問点

配列って何か?連想配列って何?なんのためにある概念?それができると何ができるようになるの?

それができると何ができるようになるの?

配列と連想配列を使うと、複数のデータ集合を扱うことができる。

配列って何か?

配列は、要素にインデックス番号でアクセスすることができるようになる。

連想配列って何?

連想配列は、要素にキー(名前)でアクセスすることができるようになる

 

おそらくこの概念はpythonで言うlist型のデータや辞書型のデータの扱いについて関連するものかもしれない。

配列の扱い方

配列インスタンスの生成方法

ドキュメント:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array#Syntax

配列のインスタンスの生成方法はpythonのように[]を使う方法と、Arrayオブジェクトに引数を入れて生成する方法の2通りがある。

var moji = ["A", "B", "C", "D" ]; #pythonのような書き方

var moji = new Array("A", "B", "C", "D");

配列の要素取り出し

>|js| console.log(lights[0]) ||<

pythonと同じ。で、文末にセミコロンを入れるとエラーが出てしまう。要素の取り出しの際はセミコロンは不要。要素の取り出しは文として扱うなということか??

 

連想配列の作り方

var dic = {red:"赤色",white:"白色",blue:"青色",black:"黒色"}  

pythonの場合(kotlinとも)と違ってkeyが文字列だとしてもシングル、ダブルクォーテーションで書かない。ここが違う点。

 

連想配列の操作方法

pythonの辞書型データの定義とほぼ同じ。違うところは定義時に必要となるvarと文末に必要となる;に加えてキーを””でくくらなくてよいというところだけ。

UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list

以下の注意メッセージが表示される

UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list:******

解消方法

参考にしたところ:https://stackoverflow.com/questions/44033670/python-django-rest-framework-unorderedobjectlistwarning/44036414
自分の場合はdrfを利用せずにこのメッセージが出てきた。このエラーはインスタンスのリストの並び順が固定されいなく、フワフワしているためページネーションでうまくオブジェクトを表示することができないということらしい。
だからオブジェクトリストを特定のルールの並び順にして作成すれば良いとのことだった。実際に自分はProduct.objects.filter(category__startswith=c)としていた。

 

object_list = Product.objects.filter(category__startswith=c).order_by("-id")

これで注意メッセージが出なくなった。

django:adminページでインスタンスを検索する

adminでインスタンスの検索が必要になるケース

例えば運用しているアプリケーションのインスタンスに誤りがあるとする。このインスタンスを修正するためにadminから修正することになっていたとする。
この場合アドミンからインスタンスを選択し、修正を行う。しかしインスタンスが20,000件ほどあったらどうだろうか?検索できないとページを繰りながら該当インスタンスを探すことになる。200ページくらいページを繰りたいか?答えは否。

 

インスタンスを検索するフォームをアドミンに実装する

document:https://docs.djangoproject.com/ja/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields

検索フォームの実装はModelAdminを継承したクラスの属性にsearch_fieldsを定めてやるだけで終了する。

from django.contrib import admin
from products.models import Product


class ProductModelAdmin(admin.ModelAdmin):

	search_fields = ["productId"]
	


admin.site.register(Product, ProductModelAdmin)

このように書けば、新たにフォームがアドミンページに出現する。そしてproductidを打ち込むと、該当するインスタンスのみが抽出されるようになる。

この検索フォームの実装は前提条件がある。それは検索対象がCharFieldまたはTextFieldでことだ。
上記のフィールドではないフィールドを使って検索したい場合もある。その際は、クラス属性のlist_filterを使うと検索が可能になる。BooleanField、CharField、DateField、DateTimeField、IntegerField、ForeignKey、ManyToManyFieldであれば利用することができる。参考:https://docs.djangoproject.com/ja/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter