diadia

興味があることをやってみる

django[データオブジェクトの操作まとめ]

関連記事

本題:データオブジェクトの操作まとめ


動画をみて勉強していたが、ついていけなくなった。
打開策としてドキュメントを読んでみようと思う。
最初は読んでもわからなかったことも今なら少しわかることもあるだろう。

クエリを作成する | Django documentation | Django
データ系の操作ががわからない。
操作といえばデータの作成、変更、削除、検索取り出しだ。
この辺を見ていく。


データの作成方法

djangoでは自分が思うデータ作成をデータオブジェクトと読んでいる。
データオブジェクト=レコード。
データオブジェクト(オブジェクト)を作成する方法は2つ

#① 
>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()
#②
b= Blog.objects.create(name='Beatles Blog', tagline='All the latest Beatles news.')


オブジェクトに対する変更を保存する

#save()が行われないと変更が保存されない。
>>> b.name = 'New name'>>> e.delete()
>>> b.save()
この変更は変更したいレコード(この場合はb)をまずデータベースのテーブルからとってきている前提がある。
テーブルから任意のデータオブジェクトを取ってくることを「オブジェクトを取得する」とする。

オブジェクトを削除する

オブジェクトを取得するは説明事項が多いので先に削除から確認する。

>>> e.delete()
(1, {'weblog.Entry': 1})
#save()しなくても消えてしまう
#また一つじゃなくて複数消すことや全部消すこともできる
>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})
>>>Entry.objects.all().delete()

モデルのインスタンスを複製する

クエリを作成する | Django documentation | Django
モデルインスタンスを複製するためのビルトインメソッドはありませんが、すべてのフィールドの値を複製した新しいインスタンスを作成することは簡単にできます。最もシンプルなケースでは、pk を None にセットします。ブログの例を使用すると

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1

blog.pk = None
blog.save() # blog.pk == 2
#継承している場合はpk と id の両方を None にセットする必要がある。
class ThemeBlog(Blog):
    theme = models.CharField(max_length=200)

django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
django_blog.save() # django_blog.pk == 3

django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4

オブジェクトを取得する

オブジェクトを取得すると言っても上の例のように、オブジェクト1つだけと限らず、3つだったり、条件を満たすものだけ取得する場合がある。
https://docs.djangoproject.com/ja/2.1/topics/db/queries/#retrieving-objects

>>> x=Cart.objects.create()
>>> x
<Cart: 11>  #データオブジェクト(レコード)は<モデル名:ID番号>で表される。

>>> z = Cart.objects.filter(id=11)
>>> z
<QuerySet [<Cart: 11>]> #結論:フィルターをかけるとクエリセットが返ってくる


#クエリセットからどうやってオブジェクトを引き出すか?
>>> z.first()
<Cart: 11> #結論:クエリセットにfirst()をかけるとオブジェクトを引き出せる

>>> z.get(id=11)
<Cart: 11> #結論:クエリセットにget()をかけるとオブジェクトを引き出せる

次に気になるのはどうやってデータオブジェクトのフィールドを参照するのか?
答えはデータオブジェクト(レコード)にカラムを指定するとフィールドを参照できる。
ただすべてこの限りではない。

>>> x.id
11
#結論:データオブジェクトにカラムをかけ合わせればフィールドを参照できる

# フィールドに入ってない情報を参照するとどうなるか?
>>> x.user #結論:何も返ってこない
>>> type(x.user)
<class 'NoneType'>


#注意:ManyToManyFieldとしている場合の参照方法
#前提:ManyToManyFieldにいくつか製品を予め登録してあります
>>> x.products
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x10ec8cef0>

#解決策:fieldに複数入っているものを選択する(テーブルからクエリセットするように)
>>> x.products.all()
<QuerySet [<Product: camera>, <Product: TV>, <Product: cellphone>, <Product: Hair dryer>]>

>>> y=x.products.all()
>>> for t in y:
...     print(t)
... 
camera
TV
cellphone
Hair dryer

#クエリセット状態ならfor構文を使用することができる。
>>> for t in y:
...     print(t.price)
... 
39.99
39.99
39.99
39.99

もっと大きな視点で考えてみる。
データを作成する場合

data_object = Blog(name="Hoy,Buen dia", content=" Hoy nos vemos .el vive ....." )
data_object.save()
または
data_object=Blog.objects.create(name="Hoy,Buen dia", content=" Hoy nos vemos .el vive ....." )

こんな感じで作ってきた。これはviews.pyに組み込んだり、django のshellで実行したりしてデータオブジェクトを作成するパターンだ。もちろん他にも方法がある。adminからデータを作成する場合もある。確認はそれぐらいにしておいて、自分が気づいたのは以下のこと。上記の方法はデータ作成主体が自分またはサイト運営者である。ただデータを作成する主体はユーザもいる。このユーザによって作成され、特定の場合の為にシグナルやm2m_changedっていうキーワードが必要になってくるのではないか?

ユーザがデータ作成するときにsignalsが必要になるという過程に基づいて勉強を進める。
signals
Signals | Django documentation | Django


pre_save()について
https://docs.djangoproject.com/ja/2.1/ref/signals/#pre-save
リレーション関係のものは以下のような感じで、定義とともにコネクトの一文を入れることが原則のようだ。

def pre_save_total(sender, instance, *args, **kwargs):
obj = instance
.....

pre_save.connect(Hoge, sender=class_name)




get_queryset()について

本来の使い方かどうかはわからないけれども、以下のように使っている。
その使い方は、クエリセットの修正だ。
ListViewにはget_queryset()なるものがあるらしい。
ListViewをそのまま使うとget_queryset()の結果が返される。
get_queryset()はClass.objects.all()で作られている。自分のほしいクエリセットを返したければget_queryset()を上書き保存する必要がある。
この上書き時にget_queryset()を書くことになる。
これはデータベースの検索のようなときに使う。



・Methods that do not return QuerySets
https://docs.djangoproject.com/ja/2.1/ref/models/querysets/#methods-that-do-not-return-querysets
データベースを扱う上で命令の結果がクエリセットで返ってくるか、データオブジェクトで返ってくるかは非常に重要で覚えるべきものだ。
だからShellを用いて結果がクエリセットかデータオブジェクトかをメモして覚えていた。
しかしながらdjangoのドキュメントにその区別を明確にするものがあった。
クエリセットで返すものとその他で区別されている。
今回はドキュメントの中でよく目に触れるものを列挙してみる。
get()
オブジェクトを返す
create()
オブジェクトを返す
get_or_create()
オブジェクトを返す
update_or_create()
count()
整数を返す
latest()
first()
last()
exists()
delete()