DynamoDB PutItem di Python (boto3)

put_item menulis satu item utuh dan mengganti item mana pun yang punya primary key sama (aksi berbasis item membahas bedanya dengan update_item). Dengan client tingkat rendah, setiap atribut diberikan sebagai DynamoDB JSON, dan boto3 memeriksa bentuk itu secara lokal sebelum apa pun dikirim.

Kode

import boto3
from botocore.exceptions import ClientError

client = boto3.client("dynamodb")

try:
    client.put_item(
        TableName="Music",
        Item={"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}, "AlbumTitle": {"S": "Danzon"}, "Year": {"N": "1994"}, "Awards": {"N": "0"}},
        ConditionExpression="attribute_not_exists(#cond0) AND attribute_not_exists(#cond1)",
        ExpressionAttributeNames={"#cond0": "Artist", "#cond1": "SongTitle"},
    )
    print("Song written")
except ClientError as err:
    if err.response["Error"]["Code"] == "ConditionalCheckFailedException":
        print("A song with that key already exists — not overwritten")
    else:
        raise

Penjelasan

{"N": 1994} tidak pernah sampai ke AWS, dan except ClientError tidak akan menangkapnya. Botocore memvalidasi permintaan terhadap model layanannya sendiri lebih dulu, dan int Python di tempat tipe N menginginkan string gagal di sana:

ParamValidationError: Parameter validation failed:
Invalid type for parameter Item.Year.N, value: 1994, type: <class 'int'>, valid types: <class 'str'>

ParamValidationError turunan dari BotoCoreError, bukan ClientError, jadi handler dalam cuplikan di atas meloloskannya. Itu biasanya memang yang Anda mau, karena ini bug dan bukan hasil bisnis, tetapi artinya try/except ClientError di sekitar sebuah penulisan bukanlah penangkap segalanya. Sisi baiknya, error itu menyebut jalur persisnya, Item.Year.N, yang untuk debugging mengalahkan ValidationException dari sisi server. Selengkapnya di "Parameter validation failed".

Permukaan lengkap dari kondisi yang gagal. Menangkap put bersyarat yang sama dua kali dan mencetak semua isi exception-nya menghasilkan:

type(e).__name__                              ConditionalCheckFailedException
e.response["Error"]["Code"]                   ConditionalCheckFailedException
e.response["Error"]["Message"]                The conditional request failed
e.response["ResponseMetadata"]["HTTPStatusCode"]  400
str(e)                                        An error occurred (ConditionalCheckFailedException) when calling the PutItem operation: The conditional request failed

Dua hal mengikuti dari situ. Pada botocore 1.43.58 objeknya adalah subclass yang dimodelkan, jadi except client.exceptions.ConditionalCheckFailedException bekerja berdampingan dengan pemeriksaan err.response["Error"]["Code"] yang dipakai cuplikan itu; pilih salah satu dan konsistenlah. Dan str(e) adalah kalimat yang sudah diformat, bukan pesan layanan, jadi jangan pernah membandingkannya dengan sebuah literal.

Kondisi yang gagal tetap menagih sebuah penulisan. AWS: "if the expression evaluates to false, DynamoDB still consumes write capacity units from the table" (diambil 2026-07-28). Loop percobaan ulang create-only membayar setiap upaya yang ditolak. Sebagai gambaran skalanya, put yang berhasil atas item ~15 KB melaporkan "CapacityUnits": 15 di bawah ReturnConsumedCapacity="TOTAL"; penulisan dibulatkan ke atas per 1 KB, bukan per 4 KB seperti pembacaan.

API resource adalah kontrak yang berbeda, dan float adalah tempat Anda menyadarinya. boto3.resource("dynamodb").Table("Music").put_item(Item={...}) menerima Python biasa dan melakukan marshalling untuk Anda, tetapi ia menolak floating point biner mentah-mentah:

TypeError: Float types are not supported. Use Decimal types instead.

Bungkus nilainya dengan decimal.Decimal("4.5"), dari sebuah string dan bukan dari float, atau ketidaktepatannya sudah terlanjur menempel sebelum Decimal melihatnya. Membaca kembali lewat API yang sama mengembalikan setiap angka sebagai Decimal, yang merupakan perubahan nyata pada kode Anda, bukan sekadar detail format. Lihat "Float types are not supported".

Mencampur kedua API adalah jebakan yang tak diperingatkan keduanya. Client tingkat rendah dengan senang hati menerima {"N": "1.5"}, nilai yang akan ditolak API resource sebagai float. Codebase yang menulis dengan yang satu dan membaca dengan yang lain akan menerima Decimal dari data yang tidak pernah melewati Decimal saat masuk.

Alias #cond0 bukan hiasan. Mereka mengarah ke Artist/SongTitle lewat ExpressionAttributeNames. Nama atribut inline bekerja sampai salah satunya bertabrakan dengan kata reserved, lalu expression-nya gagal pada nama yang tidak Anda ubah.

Lakukan secara visual

Condition expression adalah tempat penulisan manual pertama kali tersesat, karena yang salah gagal sebagai penulisan yang ditolak alih-alih sebagai error sintaks. DynamoDB Expression Builder gratis merakit ConditionExpression beserta map nama dan nilainya dan memancarkan panggilan boto3 siap tempel.

Untuk menulis dan menyunting item terhadap tabel Anda sendiri — satu formulir per atribut, pemilih tipe, salin hasilnya kembali sebagai boto3 — unduh DynoTable.

Panduan terkait

Referensi

Direproduksi 2026-07-28 dengan boto3 1.43.58 / botocore 1.43.58 terhadap DynamoDB Local (amazon/dynamodb-local) di port 9000. Teks exception, field respons, dan pembacaan kapasitasnya adalah keluaran yang ditangkap, disalin apa adanya.

Bekerja dengan DynamoDB tanpa Console

Klien desktop DynamoDB yang cepat dan menjalankan SQL sungguhan yang tidak bisa dijalankan DynamoDB — JOINs, GROUP BY, agregasi — dengan editing visual dan agen AI pada kunci Bedrock milik Anda sendiri.

Uji coba gratis 30 hari, tanpa kartu kredit — lalu paket Free tanpa batas waktu.