1. TOP
  2. ブログ
  3. Django SQL データベース INSERT UPDATE 追加更新方法 save() create() add() update()

Django SQL データベース INSERT UPDATE 追加更新方法 save() create() add() update()

更新日:2021年2月1日

Djangoで、データベースのデータを追加挿入(INSERT)および更新(UPDATE)する方法をDjangoの公式ドキュメントを参考にしてまとめました。
save()、create()、add()、update()、get_or_create()、update_or_create()、bulk_create()の書き方と注意事項についてまとめています。

環境:Python3.8.2 Django3.1

データの追加挿入(INSERT)と更新(UPDATE)に使用するにメソッド

save()追加または更新
create()オブジェクトの作成と保存を一つの処理で行う
add()ManyToManyFieldのデータ追加
update()一括更新
get_or_create()データを取得、なければ追加
update_or_create()データを更新、なければ追加
bulk_create()一括追加

save():データをINSERT(既にプライマリーキーのデータがある場合はUPDATE)

記載例

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

上記の例では、save()がされた時にINSERT SQL 文が実行されます。
save()メソッドは値を返しません。

なお、既にプライマリキーがあるデータの条件を指定した場合は、INSERTでなく
UPDATE SQL 文が実行されます。

更新(UPDATE)の例は下記です。

save():データを更新(UPDATE)する方法

記載例

>>> b5.name = 'New name'
>>> b5.save()

上記の例では、明示的にsave()が呼ばれた時にはじめて UPDATE SQL 文が実行されます。


オブジェクトの作成と保存を一つの処理で行う create()メソッド

オブジェクトの作成と保存を一つの処理で行うには、create()メソッドを使用します。

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

上記の例は、下記と等価です。

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)


get_or_create() データを取得なければ追加

データを取得、なければ追加の処理は、get_or_create()メソッドでできます。

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()
上記は下記と等価で
obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

John Lennonという名前のデータがあれば取得、なければ誕生日を 1940年10月9日にして追加となります。

結果を(Object, created) のタプルで返して、Objectは、取得したものか追加したものです。
"created"はそのObjectが追加したものかどうかのBoolean(TrueかFalse)で、
追加した場合 Trueとなります。

update_or_create() データを更新なければ追加

defaults = {'first_name': 'Bob'}
try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in defaults.items():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    new_values = {'first_name': 'John', 'last_name': 'Lennon'}
    new_values.update(defaults)
    obj = Person(**new_values)
    obj.save()

上記は下記と等価で

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

データがあればfirst_nameを'Bob'に更新、なければ、first_name='Bob'、last_name='Lennon'のデータを追加します。

結果を(Object, created) のタプルで返して、Objectは、更新されたものか追加したものです。
"created"はそのObjectが追加されたものかどうかのBoolean(TrueかFalse)で、
追加した場合 Trueとなります。


bulk_create():複数レコードの一括INSERT

bulk_create()で、複数データのリストを1クエリで一括追加します。
Entry.objects.bulk_create([
    Entry(headline='This is a test'),
    Entry(headline='This is only a test'),
])


ForeignKeyフィールドに対する更新

ForeignKeyフィールドを更新する場合は、対象とするフィールドに適した型のオブジェクトを入力するだけです。

>>> from blog.models import Blog, Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

上記の場合は、entryモデルのblogを、Blogモデルのオブジェクトで更新します。

ManyToManyFieldに対する更新

ManyToManyField に対する更新は通常のフィールド更新とは少し異なります。 リレーションのためレコードを追加するには add() メソッドを対象となるフィールドに対して使用します。 以下の例では entry オブジェクトに Author のインスタンス joe を追加します。
>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)

ManyToManyField に対して複数のレコードを一度に追加するには、add() 呼び出し時に複数の引数を次の例のように含めます。

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)

もし間違った型のオブジェクトを設定もしくは追加しようとすると Django はエラーを発生させます。


複数のオブジェクトを一括で更新

QuerySetのすべてのオブジェクトに特定の値をセットしたい場合は、update()を使用します。

# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

このメソッドを使用して更新できるのは外部制約のない非リレーションのフィールドと ForeignKeyフィールドだけです。
非リレーションのフィールドを更新するには、定数として新しい値をセットします。
ForeignKey フィールドを更新するには、関係づけたい新しいモデルインスタンスを新しい値にセットします。

下記例では、Entryモデルの ForeignKeyフィールドblogを全て更新します。
>>> b = Blog.objects.get(pk=1)

# Change every Entry so that it belongs to this Blog.
>>> Entry.objects.all().update(blog=b)

update() は即座に適用され、クエリに一致した行数を返します。

update()で更新する QuerySet の制限

update()で更新する QuerySet の唯一の制限は、1 つのデータベーステーブル (モデルのメインテーブル) にしかアクセスできないことです。
関係フィールドでフィルタすることもできますが、モデルのメインテーブルのカラムしか更新できません。

>>> b = Blog.objects.get(pk=1)

# Update all the headlines belonging to this Blog.
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')

update() は直接 SQL 命令文に変換されて、直接更新する一括操作となります。
save() の実行は必要ありません。


モデル内の別のフィールドの値に基づいてフィールドを更新

F 式 を使ってモデル内の別のフィールドの値に基づいてフィールドを更新できます。

>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

上記はEntryモデルのn_pingbacksを1カウントアップする例です。

ただし、filter および exclude 節での F() オブジェクトとは異なり、更新で F() オブジェクトを使うときには join を導入することはできません。
できるのは、更新されるモデルに関係付いたフィールドを参照することだけです。
F() オブジェクトで join の導入を試みた場合、FieldErrorとなります。

# This will raise a FieldError
>>> Entry.objects.update(headline=F('blog__name'))

上記はFieldErrorとなります。


ForeignKey フィールドにNULLを設定

ForeignKey フィールドの定義に null=True(NULL許可)がセットされている場合、None を割り当ててリレーションを削除できます。

>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ~;"


B!

前の記事:Django SQL データベース DELETEによるデータ削除方法 delete() 操作 まとめ 入門

次の記事:Django SQL データベース フィールド名に別名つける F()式