[{"data":1,"prerenderedAt":967},["ShallowReactive",2],{"writing-2026-07-17-a-reliable-way-to-prevent-duplicate-database-records":3,"writing-surroundings-2026-07-17-a-reliable-way-to-prevent-duplicate-database-records":961},{"id":4,"title":5,"body":6,"date":947,"description":948,"draft":949,"extension":950,"image":951,"meta":952,"navigation":495,"path":953,"seo":954,"stem":955,"tags":956,"updated":951,"__hash__":960},"writing\u002Fwriting\u002F2026-07-17-a-reliable-way-to-prevent-duplicate-database-records.md","A Reliable Way to Prevent Duplicate Database Records",{"type":7,"value":8,"toc":936},"minimark",[9,13,22,25,53,69,76,81,84,88,91,141,144,155,261,264,268,271,335,338,346,357,371,375,378,444,455,461,755,766,770,773,855,858,862,865,871,874,878,884,898,904,915,919,922,926,932],[10,11,12],"p",{},"Every transactional system must answer one question:",[14,15,16],"blockquote",{},[10,17,18],{},[19,20,21],"strong",{},"If the same request arrives twice, will the database contain one record or two?",[10,23,24],{},"Duplicate requests happen for many reasons — and a double-click is only the most visible one:",[26,27,28,32,35,38,41,44,47,50],"ul",{},[29,30,31],"li",{},"Double-clicks on a save button",[29,33,34],{},"Browser retries after a timeout",[29,36,37],{},"Network interruptions and reconnects",[29,39,40],{},"Reverse proxy or load balancer retries",[29,42,43],{},"Mobile clients resending after losing signal",[29,45,46],{},"Frontend bugs firing a request twice",[29,48,49],{},"API consumers retrying failed calls",[29,51,52],{},"Webhook providers resending events",[10,54,55,56,60,61,64,65,68],{},"You cannot prevent duplicate ",[57,58,59],"em",{},"requests",". You can only prevent duplicate ",[57,62,63],{},"records",". The answer is ",[19,66,67],{},"idempotency, enforced by the database",".",[10,70,71,72,75],{},"Throughout this article, keep one distinction in mind: ",[19,73,74],{},"Django handles validation. PostgreSQL guarantees correctness."," We'll implement the pattern in an invoice module as our example, but it applies to any create endpoint.",[77,78,80],"h2",{"id":79},"the-problem","The Problem",[10,82,83],{},"A user saves an invoice. The request is slow, the request is retried — by the user, the browser, or the network — and now two identical invoices exist. Reports, inventory, and accounting are all wrong. The same failure can hit orders, payments, registrations, or any other module that creates data.",[77,85,87],{"id":86},"why-client-side-prevention-isnt-enough","Why Client-Side Prevention Isn't Enough",[10,89,90],{},"Disabling the save button while a request is in flight is good UX and stops most accidental double-clicks:",[92,93,98],"pre",{"className":94,"code":95,"language":96,"meta":97,"style":97},"language-html shiki shiki-themes min-light min-dark","\u003Cbutton :disabled=\"saving\" @click=\"save\">Save\u003C\u002Fbutton>\n","html","",[99,100,101],"code",{"__ignoreMap":97},[102,103,106,110,114,118,122,125,128,130,133,136,138],"span",{"class":104,"line":105},"line",1,[102,107,109],{"class":108},"sHHeI","\u003C",[102,111,113],{"class":112},"sxIrz","button",[102,115,117],{"class":116},"sScJk"," :disabled",[102,119,121],{"class":120},"se1w0","=",[102,123,124],{"class":112},"\"saving\"",[102,126,127],{"class":116}," @click",[102,129,121],{"class":120},[102,131,132],{"class":112},"\"save\"",[102,134,135],{"class":108},">Save\u003C\u002F",[102,137,113],{"class":112},[102,139,140],{"class":108},">\n",[10,142,143],{},"But it does nothing against network retries, refreshes, proxies, or other API consumers. The frontend can reduce duplicates; it can never guarantee anything.",[10,145,146,147,150,151,154],{},"What the frontend ",[57,148,149],{},"can"," usefully do is give each operation an identity. Generate an ",[19,152,153],{},"idempotency key"," when the operation begins — not when the request is sent — and reuse it for every attempt:",[92,156,160],{"className":157,"code":158,"language":159,"meta":97,"style":97},"language-javascript shiki shiki-themes min-light min-dark","data() {\n  return {\n    invoice: {},\n    idempotencyKey: crypto.randomUUID(), \u002F\u002F once per operation\n  };\n},\nmethods: {\n  async save() {\n    await axios.post('\u002Fapi\u002Finvoices\u002F', this.invoice, {\n      headers: { 'X-Idempotency-Token': this.idempotencyKey },\n    });\n  },\n  newInvoice() {\n    this.invoice = {};\n    this.idempotencyKey = crypto.randomUUID(); \u002F\u002F reset only here\n  },\n},\n","javascript",[99,161,162,167,173,179,185,191,197,203,209,215,221,227,233,239,245,251,256],{"__ignoreMap":97},[102,163,164],{"class":104,"line":105},[102,165,166],{},"data() {\n",[102,168,170],{"class":104,"line":169},2,[102,171,172],{},"  return {\n",[102,174,176],{"class":104,"line":175},3,[102,177,178],{},"    invoice: {},\n",[102,180,182],{"class":104,"line":181},4,[102,183,184],{},"    idempotencyKey: crypto.randomUUID(), \u002F\u002F once per operation\n",[102,186,188],{"class":104,"line":187},5,[102,189,190],{},"  };\n",[102,192,194],{"class":104,"line":193},6,[102,195,196],{},"},\n",[102,198,200],{"class":104,"line":199},7,[102,201,202],{},"methods: {\n",[102,204,206],{"class":104,"line":205},8,[102,207,208],{},"  async save() {\n",[102,210,212],{"class":104,"line":211},9,[102,213,214],{},"    await axios.post('\u002Fapi\u002Finvoices\u002F', this.invoice, {\n",[102,216,218],{"class":104,"line":217},10,[102,219,220],{},"      headers: { 'X-Idempotency-Token': this.idempotencyKey },\n",[102,222,224],{"class":104,"line":223},11,[102,225,226],{},"    });\n",[102,228,230],{"class":104,"line":229},12,[102,231,232],{},"  },\n",[102,234,236],{"class":104,"line":235},13,[102,237,238],{},"  newInvoice() {\n",[102,240,242],{"class":104,"line":241},14,[102,243,244],{},"    this.invoice = {};\n",[102,246,248],{"class":104,"line":247},15,[102,249,250],{},"    this.idempotencyKey = crypto.randomUUID(); \u002F\u002F reset only here\n",[102,252,254],{"class":104,"line":253},16,[102,255,232],{},[102,257,259],{"class":104,"line":258},17,[102,260,196],{},[10,262,263],{},"One operation, one key. If you generate the key per request (for example, in a global Axios interceptor), every retry looks like a new operation and the server cannot deduplicate it.",[77,265,267],{"id":266},"why-checking-first-doesnt-work","Why Checking First Doesn't Work",[10,269,270],{},"The intuitive backend approach is to check before inserting:",[92,272,276],{"className":273,"code":274,"language":275,"meta":97,"style":97},"language-python shiki shiki-themes min-light min-dark","if not Invoice.objects.filter(idempotency_key=token).exists():\n    Invoice.objects.create(idempotency_key=token, ...)\n","python",[99,277,278,314],{"__ignoreMap":97},[102,279,280,283,286,289,292,295,297,300,303,305,308,311],{"class":104,"line":105},[102,281,282],{"class":120},"if",[102,284,285],{"class":120}," not",[102,287,288],{"class":108}," Invoice",[102,290,68],{"class":291},"som3e",[102,293,294],{"class":108},"objects",[102,296,68],{"class":291},[102,298,299],{"class":116},"filter",[102,301,302],{"class":291},"(idempotency_key",[102,304,121],{"class":120},[102,306,307],{"class":291},"token).",[102,309,310],{"class":116},"exists",[102,312,313],{"class":291},"():\n",[102,315,316,319,321,323,325,328,330,332],{"class":104,"line":169},[102,317,318],{"class":108},"    Invoice",[102,320,68],{"class":291},[102,322,294],{"class":108},[102,324,68],{"class":291},[102,326,327],{"class":116},"create",[102,329,302],{"class":291},[102,331,121],{"class":120},[102,333,334],{"class":291},"token, ...)\n",[10,336,337],{},"Under concurrency, this fails:",[92,339,344],{"className":340,"code":342,"language":343},[341],"language-text","Request A arrives\n    ↓\nexists() → false\n                        Request B arrives\n                            ↓\n                        exists() → false\nA inserts row\n                        B inserts row   ← duplicate\n","text",[99,345,342],{"__ignoreMap":97},[10,347,348,349,352,353,356],{},"Both requests pass the check before either inserts. This \"check-then-act\" race applies equally to cache-based deduplication (",[99,350,351],{},"cache.get()"," then ",[99,354,355],{},"cache.set()","). No application-level check can fix this, because the check and the insert are two separate steps — and another request can run between them.",[10,358,359,366,367,370],{},[19,360,361,362,365],{},"A note on ",[99,363,364],{},"get_or_create()",":"," many Django developers reach for it here, but it doesn't replace idempotency. Internally it's still a lookup followed by an insert, and it only helps when the lookup fields already represent business uniqueness. An idempotency key is different: it identifies a single ",[57,368,369],{},"client operation",", regardless of the record's contents.",[77,372,374],{"id":373},"let-postgresql-guarantee-uniqueness","Let PostgreSQL Guarantee Uniqueness",[10,376,377],{},"The fix is to move the guarantee into the database:",[92,379,381],{"className":273,"code":380,"language":275,"meta":97,"style":97},"class Invoice(models.Model):\n    idempotency_key = models.UUIDField(unique=True, db_index=True)\n    # ... your fields\n",[99,382,383,404,438],{"__ignoreMap":97},[102,384,385,388,390,393,396,398,401],{"class":104,"line":105},[102,386,387],{"class":120},"class",[102,389,288],{"class":116},[102,391,392],{"class":108},"(",[102,394,395],{"class":116},"models",[102,397,68],{"class":291},[102,399,400],{"class":116},"Model",[102,402,403],{"class":108},"):\n",[102,405,406,409,411,414,416,419,422,424,428,431,433,435],{"class":104,"line":169},[102,407,408],{"class":108},"    idempotency_key ",[102,410,121],{"class":120},[102,412,413],{"class":108}," models",[102,415,68],{"class":291},[102,417,418],{"class":116},"UUIDField",[102,420,421],{"class":291},"(unique",[102,423,121],{"class":120},[102,425,427],{"class":426},"svlcY","True",[102,429,430],{"class":291},", db_index",[102,432,121],{"class":120},[102,434,427],{"class":426},[102,436,437],{"class":291},")\n",[102,439,440],{"class":104,"line":175},[102,441,443],{"class":442},"srwKs","    # ... your fields\n",[10,445,446,447,450,451,454],{},"Why does this work when application checks don't? Because PostgreSQL performs the uniqueness check and the insert as a ",[19,448,449],{},"single atomic operation inside the database engine",". Two concurrent transactions cannot both insert the same unique value — one succeeds, the other fails with an ",[99,452,453],{},"IntegrityError",". There is no gap between the check and the insert, so a race condition is impossible.",[10,456,457,458,460],{},"So instead of treating ",[99,459,453],{}," as a failure, we treat it as a signal that the work is already done:",[92,462,464],{"className":273,"code":463,"language":275,"meta":97,"style":97},"from django.db import IntegrityError, transaction\n\ndef create(self, request):\n    token = request.headers.get(\"X-Idempotency-Token\")\n    if not token:\n        return Response({\"detail\": \"Idempotency token required.\"}, status=400)\n\n    serializer = InvoiceSerializer(data=request.data)\n    serializer.is_valid(raise_exception=True)\n\n    try:\n        with transaction.atomic():\n            invoice = serializer.save(idempotency_key=token)\n    except IntegrityError:\n        invoice = Invoice.objects.get(idempotency_key=token)\n        return Response(InvoiceSerializer(invoice).data, status=200)\n\n    return Response(InvoiceSerializer(invoice).data, status=201)\n",[99,465,466,491,497,518,544,557,588,592,610,629,633,640,655,677,686,709,730,734],{"__ignoreMap":97},[102,467,468,471,474,476,479,482,485,488],{"class":104,"line":105},[102,469,470],{"class":120},"from",[102,472,473],{"class":108}," django",[102,475,68],{"class":291},[102,477,478],{"class":108},"db ",[102,480,481],{"class":120},"import",[102,483,484],{"class":108}," IntegrityError",[102,486,487],{"class":291},",",[102,489,490],{"class":108}," transaction\n",[102,492,493],{"class":104,"line":169},[102,494,496],{"emptyLinePlaceholder":495},true,"\n",[102,498,499,502,505,507,511,513,516],{"class":104,"line":175},[102,500,501],{"class":120},"def",[102,503,504],{"class":116}," create",[102,506,392],{"class":108},[102,508,510],{"class":509},"sip0z","self",[102,512,487],{"class":291},[102,514,515],{"class":509}," request",[102,517,403],{"class":108},[102,519,520,523,525,527,529,532,534,537,539,542],{"class":104,"line":181},[102,521,522],{"class":108},"    token ",[102,524,121],{"class":120},[102,526,515],{"class":108},[102,528,68],{"class":291},[102,530,531],{"class":108},"headers",[102,533,68],{"class":291},[102,535,536],{"class":116},"get",[102,538,392],{"class":291},[102,540,541],{"class":112},"\"X-Idempotency-Token\"",[102,543,437],{"class":291},[102,545,546,549,551,554],{"class":104,"line":187},[102,547,548],{"class":120},"    if",[102,550,285],{"class":120},[102,552,553],{"class":108}," token",[102,555,556],{"class":291},":\n",[102,558,559,562,565,568,571,574,577,580,582,586],{"class":104,"line":193},[102,560,561],{"class":120},"        return",[102,563,564],{"class":116}," Response",[102,566,567],{"class":291},"({",[102,569,570],{"class":112},"\"detail\"",[102,572,573],{"class":291},": ",[102,575,576],{"class":112},"\"Idempotency token required.\"",[102,578,579],{"class":291},"}, status",[102,581,121],{"class":120},[102,583,585],{"class":584},"soJJD","400",[102,587,437],{"class":291},[102,589,590],{"class":104,"line":199},[102,591,496],{"emptyLinePlaceholder":495},[102,593,594,597,599,602,605,607],{"class":104,"line":205},[102,595,596],{"class":108},"    serializer ",[102,598,121],{"class":120},[102,600,601],{"class":116}," InvoiceSerializer",[102,603,604],{"class":291},"(data",[102,606,121],{"class":120},[102,608,609],{"class":291},"request.data)\n",[102,611,612,615,617,620,623,625,627],{"class":104,"line":211},[102,613,614],{"class":108},"    serializer",[102,616,68],{"class":291},[102,618,619],{"class":116},"is_valid",[102,621,622],{"class":291},"(raise_exception",[102,624,121],{"class":120},[102,626,427],{"class":426},[102,628,437],{"class":291},[102,630,631],{"class":104,"line":217},[102,632,496],{"emptyLinePlaceholder":495},[102,634,635,638],{"class":104,"line":223},[102,636,637],{"class":120},"    try",[102,639,556],{"class":291},[102,641,642,645,648,650,653],{"class":104,"line":229},[102,643,644],{"class":120},"        with",[102,646,647],{"class":108}," transaction",[102,649,68],{"class":291},[102,651,652],{"class":116},"atomic",[102,654,313],{"class":291},[102,656,657,660,662,665,667,670,672,674],{"class":104,"line":235},[102,658,659],{"class":108},"            invoice ",[102,661,121],{"class":120},[102,663,664],{"class":108}," serializer",[102,666,68],{"class":291},[102,668,669],{"class":116},"save",[102,671,302],{"class":291},[102,673,121],{"class":120},[102,675,676],{"class":291},"token)\n",[102,678,679,682,684],{"class":104,"line":241},[102,680,681],{"class":120},"    except",[102,683,484],{"class":108},[102,685,556],{"class":291},[102,687,688,691,693,695,697,699,701,703,705,707],{"class":104,"line":247},[102,689,690],{"class":108},"        invoice ",[102,692,121],{"class":120},[102,694,288],{"class":108},[102,696,68],{"class":291},[102,698,294],{"class":108},[102,700,68],{"class":291},[102,702,536],{"class":116},[102,704,302],{"class":291},[102,706,121],{"class":120},[102,708,676],{"class":291},[102,710,711,713,715,717,720,723,725,728],{"class":104,"line":253},[102,712,561],{"class":120},[102,714,564],{"class":116},[102,716,392],{"class":291},[102,718,719],{"class":116},"InvoiceSerializer",[102,721,722],{"class":291},"(invoice).data, status",[102,724,121],{"class":120},[102,726,727],{"class":584},"200",[102,729,437],{"class":291},[102,731,732],{"class":104,"line":258},[102,733,496],{"emptyLinePlaceholder":495},[102,735,737,740,742,744,746,748,750,753],{"class":104,"line":736},18,[102,738,739],{"class":120},"    return",[102,741,564],{"class":116},[102,743,392],{"class":291},[102,745,719],{"class":116},[102,747,722],{"class":291},[102,749,121],{"class":120},[102,751,752],{"class":584},"201",[102,754,437],{"class":291},[10,756,757,758,761,762,765],{},"First request: ",[99,759,760],{},"201 Created",". Any replay: ",[99,763,764],{},"200 OK"," with the same record. Django validated the request; PostgreSQL guaranteed the correctness.",[77,767,769],{"id":768},"add-business-constraints","Add Business Constraints",[10,771,772],{},"One layer of protection is good; two are better. Most records also have a natural uniqueness rule of their own. Enforce it as a second constraint:",[92,774,776],{"className":273,"code":775,"language":275,"meta":97,"style":97},"class Meta:\n    constraints = [\n        models.UniqueConstraint(\n            fields=[\"terminal_id\", \"number\"],\n            name=\"unique_invoice_per_terminal\",\n        )\n    ]\n",[99,777,778,787,797,810,832,845,850],{"__ignoreMap":97},[102,779,780,782,785],{"class":104,"line":105},[102,781,387],{"class":120},[102,783,784],{"class":116}," Meta",[102,786,556],{"class":108},[102,788,789,792,794],{"class":104,"line":169},[102,790,791],{"class":108},"    constraints ",[102,793,121],{"class":120},[102,795,796],{"class":108}," [\n",[102,798,799,802,804,807],{"class":104,"line":175},[102,800,801],{"class":108},"        models",[102,803,68],{"class":291},[102,805,806],{"class":116},"UniqueConstraint",[102,808,809],{"class":291},"(\n",[102,811,812,815,817,820,823,826,829],{"class":104,"line":181},[102,813,814],{"class":291},"            fields",[102,816,121],{"class":120},[102,818,819],{"class":291},"[",[102,821,822],{"class":112},"\"terminal_id\"",[102,824,825],{"class":291},", ",[102,827,828],{"class":112},"\"number\"",[102,830,831],{"class":291},"],\n",[102,833,834,837,839,842],{"class":104,"line":187},[102,835,836],{"class":291},"            name",[102,838,121],{"class":120},[102,840,841],{"class":112},"\"unique_invoice_per_terminal\"",[102,843,844],{"class":291},",\n",[102,846,847],{"class":104,"line":193},[102,848,849],{"class":291},"        )\n",[102,851,852],{"class":104,"line":199},[102,853,854],{"class":108},"    ]\n",[10,856,857],{},"Even if a future bug bypasses the idempotency key, PostgreSQL still refuses the duplicate. Constraints cost nothing and protect you from bugs you haven't written yet.",[77,859,861],{"id":860},"the-reusable-architecture","The Reusable Architecture",[10,863,864],{},"The complete flow, reusable in any module:",[92,866,869],{"className":867,"code":868,"language":343},[341],"Client\n    ↓  generate one idempotency key per operation\nDjango\n    ↓  validate the request\nPostgreSQL\n    ↓  unique constraint enforces exactly-once insert\nIntegrityError\n    ↓  caught by Django\nReturn the existing resource (200 OK)\n",[99,870,868],{"__ignoreMap":97},[10,872,873],{},"Every create endpoint in your system can follow this exact shape.",[77,875,877],{"id":876},"when-should-you-use-this","When Should You Use This?",[10,879,880,883],{},[19,881,882],{},"Use idempotency for"," anything where a duplicate causes damage:",[26,885,886,889,892,895],{},[29,887,888],{},"Invoices, orders, and purchase orders",[29,890,891],{},"Payments and money transfers",[29,893,894],{},"Inventory movements and shipments",[29,896,897],{},"Ticket creation and registrations",[10,899,900,903],{},[19,901,902],{},"Skip it for"," operations that are naturally safe to repeat:",[26,905,906,909,912],{},[29,907,908],{},"Search endpoints",[29,910,911],{},"Reports and analytics",[29,913,914],{},"Any read-only API",[77,916,918],{"id":917},"performance","Performance",[10,920,921],{},"A unique index check is a single, extremely fast lookup — it takes microseconds. The constraint adds no meaningful overhead to inserts, and PostgreSQL handles this pattern at high write volumes without queues, distributed locks, or any special infrastructure. For the vast majority of applications, performance is simply not a concern here.",[77,923,925],{"id":924},"key-takeaway","Key Takeaway",[10,927,928,929,931],{},"A transactional system should never rely on timing, client behavior, or network conditions to maintain data integrity — those are unpredictable. The database is the only component capable of guaranteeing uniqueness under concurrency. Generate one idempotency key per operation, enforce it with a PostgreSQL unique constraint, and catch ",[99,930,453],{}," to return the existing record. Build your API around that guarantee, and duplicate record bugs disappear permanently.",[933,934,935],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHHeI, html code.shiki .sHHeI{--shiki-default:#24292EFF;--shiki-dark:#B392F0}html pre.shiki code .sxIrz, html code.shiki .sxIrz{--shiki-default:#22863A;--shiki-dark:#FFAB70}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .se1w0, html code.shiki .se1w0{--shiki-default:#D32F2F;--shiki-dark:#F97583}html pre.shiki code .som3e, html code.shiki .som3e{--shiki-default:#212121;--shiki-dark:#BBBBBB}html pre.shiki code .svlcY, html code.shiki .svlcY{--shiki-default:#1976D2;--shiki-dark:#79B8FF}html pre.shiki code .srwKs, html code.shiki .srwKs{--shiki-default:#C2C3C5;--shiki-dark:#6B737C}html pre.shiki code .sip0z, html code.shiki .sip0z{--shiki-default:#FF9800;--shiki-dark:#FF9800}html pre.shiki code .soJJD, html code.shiki .soJJD{--shiki-default:#1976D2;--shiki-dark:#F8F8F8}",{"title":97,"searchDepth":169,"depth":169,"links":937},[938,939,940,941,942,943,944,945,946],{"id":79,"depth":169,"text":80},{"id":86,"depth":169,"text":87},{"id":266,"depth":169,"text":267},{"id":373,"depth":169,"text":374},{"id":768,"depth":169,"text":769},{"id":860,"depth":169,"text":861},{"id":876,"depth":169,"text":877},{"id":917,"depth":169,"text":918},{"id":924,"depth":169,"text":925},"2026-07-17","Why client-side guards and existence checks fail, and how a PostgreSQL unique constraint makes create endpoints idempotent.",false,"md",null,{},"\u002Fwriting\u002F2026-07-17-a-reliable-way-to-prevent-duplicate-database-records",{"title":5,"description":948},"writing\u002F2026-07-17-a-reliable-way-to-prevent-duplicate-database-records",[957,958,959],"postgresql","django","api-design","npLwT0xpHFR0ejdyODB9q8m0hhwmnffwedsoN6APYz0",[951,962],{"title":963,"path":964,"stem":965,"date":966,"children":-1},"Upload Files to Dropbox using Python","\u002Fwriting\u002F2024-03-14-upload-files-to-dropbox-using-python","writing\u002F2024-03-14-upload-files-to-dropbox-using-python","2024-03-14",1784291271594]