paint-brush
Python - Django: Та энэ зүйлийг хэзээ ч гүйлгээнд оруулах ёсгүйby@mta
Шинэ түүх

Python - Django: Та энэ зүйлийг хэзээ ч гүйлгээнд оруулах ёсгүй

by Michael T. Andemeskel17m2025/03/04
Read on Terminal Reader

Хэтэрхий урт; Унших

Гүйлгээ нь Django програмын гол хэсэг боловч хэрэв та гүйлгээнд буруу код оруулбал тасалдал үүсгэж болзошгүй!
featured image - Python - Django: Та энэ зүйлийг хэзээ ч гүйлгээнд оруулах ёсгүй
Michael T. Andemeskel HackerNoon profile picture


Агуулга

  • 1-р хэсгийн хураангуй - Джангогийн гүйлгээнд гүнзгий шумбах
  • TLDR, хураангуй
  • Гүйлгээ нь манай апп-уудад хэрхэн хор хөнөөл учруулж болох вэ?
  • онд
  • Эрсдэлтэй
  • Гадагшаа
  • Дараа нь - PSQL командууд бие биенээ хэрхэн блоклодог
  • Эх сурвалжууд

1-р хэсгийн хураангуй - Джангогийн гүйлгээнд гүнзгий шумбах

Өмнөх нийтлэлээс бид transaction.atomic -ээр чимэглэсэн функц дуудагдах үед юу болдог, мөн with transaction.atomic() юу болдог талаар олж мэдсэн. Дүгнэж хэлэхэд:


  1. DB-тэй холболт үүсгэсэн эсвэл сэргээсэн.
  2. Гүйлгээ үүсгэсэн, жишээлбэл, BEGIN; DB руу илгээгдэнэ (хэрэв DB нь PSQL эсвэл өөр SQL хувилбар бол).
  3. Одооноос эхлэн функц оршин тогтнох хүртэл эсвэл with мэдэгдэл дуусах хүртэл - алдаатай эсвэл амжилттай эсэхээс үл хамааран бид гүйлгээнд оролцох бөгөөд DB биднийг хүлээж байх болно.
  4. Энэ нь (наад зах нь PSQL гэх мэт ACID DB-ийн хувьд) гүйлгээ нь өөрчлөгдөж буй хүснэгт болон мөрүүдэд түгжээтэй байх болно гэсэн үг юм.
  5. Django DB үйлдлийг гүйцэтгэх үед DB нь харгалзах түгжээг барьж, тухайн хүснэгт эсвэл мөрөнд зөрчилтэй үйлдлүүдээс сэргийлдэг.
  6. Энэ нь түгжээг тайлахыг хүлээснээс болж бусад холболтын завсарлагад хүргэж болзошгүй.
  7. Хэрэв үйлдэл амжилтгүй болсон эсвэл ажиллах үеийн алдаа гарвал DB бүх гүйлгээг буцааж, түгжээг суллана.
  8. Хэрэв бүх гүйлгээ амжилттай болвол бүх өөрчлөлтүүд хийгдсэн бөгөөд бусад DB холболтод ашиглах боломжтой болно.
  9. Түгжээг нь суллав.


Одоо бид гүйлгээнд юу хийх, юу хийхээс зайлсхийх талаар ярилцах болно. Дараахь гүйлгээний зан үйлийн улмаас гүйлгээний блокт байршуулах үед тодорхой үйлдлүүд аюултай.


  • Гүйлгээ бүтэлгүйтэх эсвэл дуусах хүртэл гүйлгээ нь түгжээнд хадгалагдана.
  • Гүйлгээ нь бүтэлгүйтсэн үед бүх DB үйлдлүүдийг буцаана.
  • Гүйлгээний хүсэлтийг DB үйлдлийг гүйцэтгэмэгц түгжих хүсэлт гаргадаг.

TLDR, хураангуй

онд

  • МБ дээрх буцаах үйлдлүүд - Хэрэв DB үйлдлийг буцаах боломжгүй бөгөөд гүйлгээ амжилтгүй болвол гүйлгээ нь өөрчлөлтийг автоматаар буцаахыг оролдох боловч буцаах боломжгүй тул амжилтгүй болох тул DB муу төлөвт үлдэнэ.
  • DB дээр шаардлагатай холбоотой үйлдлүүд - Бид хэрэглэгчийн бүртгэлгүйгээр банкны шинэ дансны бүртгэл үүсгэх боломжгүй тул хоёуланг нь ижил гүйлгээнд үүсгэх шаардлагатай.
  • Эргэгдэх ба холбогдох бизнесийн логик - Хадгаламжтай шинэ дансны бүртгэл үүсгэсний дараа харилцагчийн нийт үлдэгдлийг тооцоолох (ухаалаг загварчлал, зохицуулалтаар үүнийг гүйлгээнээс хасаж болно).

Эрсдэлтэй

  • Удаан асуулга - Эдгээр гурван хувилбараас бусад тохиолдолд өгөгдөл татах нь ихэвчлэн хурдан байдаг. Эдгээр асуулга нь гүйлгээг удаашруулж, түгжигдэх хугацааг уртасгах бөгөөд энэ нь бусад хэрэглэгчдэд сөрөг нөлөө үзүүлэх болно.
  • Олон хүснэгт дээрх үйлдлүүд - Олон хүснэгт дээрх үйлдлүүдтэй гүйлгээ нь хүснэгт бүрийг хийгдэх хүртэл түгжих боломжтой. Энэ нь ялангуяа Джангогийн шилжилт хөдөлгөөнд түгээмэл байдаг нь шилжилт хөдөлгөөнийг бага байлгах бас нэг шалтгаан бөгөөд нэг эсвэл хэд хэдэн хүснэгтэд төвлөрдөг.
  • Өгөгдлийн шилжилт - Гүйлгээ нь асуулга хийгдсэнээс эхлэн гүйлгээ бүтэлгүйтэх эсвэл дуусах хүртэл түгжээтэй байдаг тул хүснэгтийн мөр бүр дээр ажиллах шилжилт нь мөр бүр дээр унших, бичихээс сэргийлж хүснэгтийг бүхэлд нь түгжих болно.
  • (Зөвхөн PSQL болон SQLite-д зориулагдсан*) Хүснэгт эсвэл баганыг өөрчлөх - эдгээр үйлдлүүд нь түгжээний хамгийн хатуу хэлбэрийг шаарддаг тул хүснэгтийг бүхэлд нь унших/бичихээс сэргийлнэ. Эдгээр үйлдлүүд нь тасалдал үүсгэх магадлал хамгийн өндөр байдаг.

Гадагшаа

  • Буцах боломжгүй үйлдлүүд - Гүйлгээ буцаагдсан тохиолдолд гүйлгээнд байгаа бүх зүйл буцаагдах ёстой; Хэрэв бид гүйлгээнд API дуудлага хийвэл үүнийг буцаах боломжгүй.
  • Дуудлага хаах - Гүйлгээ нь өөрчлөгдөж буй хүснэгт/мөрүүд дээр бусад бүх асуулга ажиллахаас сэргийлдэг тул гүйлгээний үргэлжлэх хугацааг уртасгах аливаа код нь DB-г түгжихэд хүргэж, DB-ээс хамааралтай аппликешнүүдэд хугацаа хэтрүүлж, хариу өгөхгүй болно.


Өөр хувилбарууд болон кодын жишээнүүдийг үргэлжлүүлэн уншаарай.

Гүйлгээ нь манай апп-уудад хэрхэн хор хөнөөл учруулж болох вэ?

Анхдагч эрсдэл нь хүснэгт болон мөрүүд дээр зөрчилдөх үйлдлээс урьдчилан сэргийлэхийн тулд гүйлгээг хийх хүртэл түгжээтэй байж, гүйлгээг буцаах боломжтой байдаг - энэ нь гүйлгээний DB-ийн үйл ажиллагааг атом хэлбэртэй болгоход зайлшгүй шаардлагатай. Энэ нь олон хүснэгт эсвэл цөөн хэдэн чухал хүснэгтүүд дээр ажилладаг урт хугацааны гүйлгээ нь түгжээг хааж, тэдгээр хүснэгт/мөрүүдийг унших/бичихээс сэргийлж тасалдал үүсгэж болзошгүй гэсэн үг юм.


Нэг ёсондоо, хэрэв бид гүйлгээний блокт буруу код оруулсан бол бид DB-тэй холбогдох бусад бүх холболтыг түүн дээр үйлдлээр нь хааснаар DB-г үр дүнтэй устгаж чадна.


Хоёрдогч эрсдэл нь гүйлгээг буцаах шаардлагатай бөгөөд буцаах боломжтой байх ёстой. Гүйлгээнд алдаа гарвал DB автоматаар үйлдэл бүрийг буцаана. Тиймээс бидний гүйлгээнд оруулсан DB-ийн үйлдлүүд буцаах боломжтой байх ёстой - ихэнх тохиолдолд бид PSQL-ийн хувьд энэ талаар санаа зовох шаардлагагүй болно. Гэхдээ бусад кодуудын талаар юу хэлэх вэ?


Ихэнхдээ бид өгөгдлөө өөрчлөхдөө үйл явдлуудыг халах, үйлчилгээг шинэчлэх, түлхэх мэдэгдэл илгээх гэх мэт даалгавруудыг хийх шаардлагатай болдог. Эдгээр ажлыг буцаах боломжгүй - бид үйл явдал, хүсэлт, мэдэгдлийг буцаах боломжгүй. Хэрэв алдаа гарвал өгөгдлийн өөрчлөлтийг буцаах боловч бид "Таны тайланг үүсгэсэн; энд дарж үзэх" гэсэн мэдэгдлийг аль хэдийн илгээсэн. Хэрэглэгч эсвэл бусад үйлчилгээнүүд энэ худал мэдээлэл дээр ажиллахад юу болох вэ? Бүтэлгүйтлийн цуваа байх болно. Тиймээс буцаах боломжгүй аливаа код нь гүйлгээнд байх ёсгүй, эс тэгвээс гүйлгээнд алдаа гарвал бид системээ муу байдалд оруулах эрсдэлтэй.

онд

  • МБ дээрх буцаах үйлдлүүд - Хэрэв DB үйлдлийг буцаах боломжгүй бөгөөд гүйлгээ амжилтгүй болвол гүйлгээ нь өөрчлөлтийг автоматаар буцаахыг оролдох боловч буцаах боломжгүй тул амжилтгүй болох тул DB муу төлөвт үлдэнэ.
  • DB дээр шаардлагатай холбоотой үйлдлүүд - Бид хэрэглэгчийн бүртгэлгүйгээр банкны шинэ дансны бүртгэл үүсгэх боломжгүй тул хоёуланг нь ижил гүйлгээнд үүсгэх шаардлагатай.
  • Эргэгдэх ба холбогдох бизнесийн логик - Хадгаламжтай шинэ дансны бүртгэл үүсгэсний дараа харилцагчийн нийт үлдэгдлийг тооцоолох (ухаалаг загварчлал, зохицуулалтаар үүнийг гүйлгээнээс хасаж болно).

Эрсдэлтэй

Эдгээр нь хэр их өгөгдөл боловсруулж байгаа болон DB урсгалаас хамааран түгжээг хэт удаан барьснаас болж тасалдал үүсгэж болзошгүй зүйлүүд юм. Эдгээр бүх зүйл хэтэрхий удаан үргэлжлэхгүй бол зүгээр.


  • Удаан асуулга — Эдгээр гурван хувилбараас бусад тохиолдолд өгөгдөл татах нь ихэвчлэн хурдан байдаг. Эдгээр асуулга нь гүйлгээг удаашруулж, түгжигдэх хугацааг уртасгах бөгөөд энэ нь бусад хэрэглэгчдэд сөрөг нөлөө үзүүлэх болно.

    • Жишээ
      • Индексжүүлээгүй баганууд дээрх асуулга
      • Том ширээн дээрх асуулга
      • Нэгдсэн
     @transaction.atomic def process_large_order_report(start_date, end_date, min_order_value=1000): # Complex query with multiple joins and aggregations large_orders = Order.objects.filter( created_at__range=(start_date, end_date), total_amount__gte=min_order_value, status='completed' ).select_related( 'customer', 'shipping_address', 'billing_address' ).prefetch_related( 'items__product__category', 'items__product__supplier' ).annotate( item_count=Count('items'), total_weight=Sum('items__product__weight'), discount_percentage=F('discount_amount') * 100 / F('total_amount') ).filter( # Additional complex filtering Q(customer__user__is_active=True) & (Q(items__product__category__name='Electronics') | Q(items__product__category__name='Furniture')) & ~Q(shipping_address__country='US') ).order_by('-total_amount') # do the transactional work with the large_orders queryset
    • Альтернатив
      • Гүйлгээ хийхээс өмнө болон гадуур эдгээр асуултуудыг хийгээрэй.
 # fixed def process_large_order_report(start_date, end_date, min_order_value=1000): # Complex query with multiple joins and aggregations large_orders = Order.objects.filter( created_at__range=(start_date, end_date), total_amount__gte=min_order_value, status='completed' ).select_related( 'customer', 'shipping_address', 'billing_address' ).prefetch_related( 'items__product__category', 'items__product__supplier' ).annotate( item_count=Count('items'), total_weight=Sum('items__product__weight'), discount_percentage=F('discount_amount') * 100 / F('total_amount') ).filter( # Additional complex filtering Q(customer__user__is_active=True) & (Q(items__product__category__name='Electronics') | Q(items__product__category__name='Furniture')) & ~Q(shipping_address__country='US') ).order_by('-total_amount') # Start the transaction block with transaction.atomic(): # do the transactional work with the large_orders queryset


  • Олон хүснэгт дээрх үйлдлүүд — олон хүснэгтүүд дээрх үйлдлүүдтэй гүйлгээ нь хүснэгт бүрийг дуусгах хүртэл түгжих боломжтой. Энэ нь ялангуяа Жангогийн шилжилт хөдөлгөөнд түгээмэл байдаг нь шилжилт хөдөлгөөнийг бага байлгах бас нэг шалтгаан бөгөөд нэг эсвэл хэд хэдэн хүснэгтэд төвлөрдөг.


    • Жишээ
      • Хүснэгт эсвэл баганын бүтцийг өөрчлөхийг үзнэ үү
     class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] # too many operations operations = [ migrations.RemoveField("Author", "age"), migrations.AddField("Author", "rating", models.IntegerField(default=0)), migrations.AlterField("Book", "price", models.DecimalField(max_digits=5, decimal_places=2)), ]
    • Альтернатив
      • Гүйлгээг хэд хэдэн жижиг гүйлгээ болгон хувааж, буцаан залгах үйл ажиллагаанд гинжлээрэй.
 # fixed # 1st migration class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] operations = [ migrations.RemoveField("Author", "age"), ] # 2nd migration class Migration(migrations.Migration): dependencies = [("migrations", "0002_initial")] operations = [ migrations.AddField("Author", "rating", models.IntegerField(default=0)), ] # 3rd migration class Migration(migrations.Migration): dependencies = [("migrations", "0003_initial")] operations = [ migrations.AlterField("Book", "price", models.DecimalField(max_digits=5, decimal_places=2)), ]


  • Өгөгдлийн шилжилт - Гүйлгээ нь асуулга хийгдсэнээс эхлэн гүйлгээ бүтэлгүйтэх эсвэл дуусах хүртэл түгжээтэй байдаг тул хүснэгтийн мөр бүр дээр ажилладаг шилжүүлэг нь мөр бүр дээр унших, бичихээс сэргийлж хүснэгтийг бүхэлд нь түгжих болно.

     def migrate_user_profiles(): # Get all users with legacy profiles users_with_profiles = User.objects.filter( legacy_profile__isnull=False ).select_related('legacy_profile') # Process all users in a single transaction with transaction.atomic(): # Track progress total = users_with_profiles.count() print(f"Migrating {total} user profiles...") # Process each user for i, user in enumerate(users_with_profiles): if i % 100 == 0: print(f"Processed {i}/{total} profiles") legacy = user.legacy_profile legacy.update_new_user_profile()
    • Альтернатив
      • Гүйлгээг бүхэлд нь шилжүүлэх биш, харин бие даасан үйлдлүүдийн эргэн тойронд хий. Гүйлгээний мөр бүрт шинэчлэлт оруулснаар бид зөвхөн богино хугацаанд түгжээг барьдаг.
 # fixed def migrate_user_profiles(): # Get all users with legacy profiles users_with_profiles = User.objects.filter( legacy_profile__isnull=False ).select_related('legacy_profile') # Process all users in a single transaction # Track progress total = users_with_profiles.count() print(f"Migrating {total} user profiles...") # Process each user for i, user in enumerate(users_with_profiles): if i % 100 == 0: print(f"Processed {i}/{total} profiles") with transaction.atomic(): legacy = user.legacy_profile legacy.update_new_user_profile()


  • ( Зөвхөн PSQL болон SQLite-д зориулагдсан *) Хүснэгт эсвэл баганыг өөрчлөх - эдгээр үйлдлүүд нь түгжээний хамгийн хатуу хэлбэрийг шаарддаг тул хүснэгтийг бүхэлд нь унших/бичихээс сэргийлнэ. Эдгээр үйлдлүүд нь тасалдал үүсгэх магадлал хамгийн өндөр байдаг.
    • Жишээ
      • Баганыг өөрчлөх
      • Хүснэгтийг өөрчлөх
    • Альтернатив
      • Тэднийг дараа ажиллуул. Эдгээр асуулга зайлшгүй шаардлагатай, ГЭХДЭЭ бид үүнийг ажлын цагаар ажиллуулах шаардлагагүй. Энд байгаа хамгийн сайн бодлого бол хүснэгт нь хэр чухал болохыг тодорхойлж, шилжилт хөдөлгөөн хэр удаан үргэлжлэхийг тооцоолж, DB хамгийн бага ачаалалтай үед шилжүүлгийг хийж, буцаах төлөвлөгөөг боловсруулах замаар тасалдал үүсэх эрсдэлийг бууруулах явдал юм.

      • Гүйлгээнд шаардагдах хугацааг багасга. Үүнийг хүснэгтийг хувааж, бие даасан хуваалтууд дээр шилжүүлэх замаар хийж болно. PSQL хуваалтууд ба Django


*Django нь зөвхөн PSQL болон SQLite-д зориулсан шилжүүлгийн эргэн тойронд гүйлгээг хийдэг.

 class Migration(migrations.Migration): dependencies = [("migrations", "0001_initial")] # this migration, if on a large table, can slow down and block other operations # do it later operations = [ migrations.RemoveField("Users", "middle_name"), ]


Гадагшаа

  • Буцааж болшгүй үйлдлүүд — Гүйлгээ буцаагдсан тохиолдолд гүйлгээний бүх зүйл буцаагдах ёстой; Хэрэв бид гүйлгээнд API дуудлага хийвэл үүнийг буцаах боломжгүй.

    • Жишээ
      • Дараалалд үйл явдал нэмэх — бусад үйл явдлыг өдөөх
      • API дуудлага илгээх — статусын шинэчлэлт, триггер ажил гэх мэт.
     def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) async_notification_service.send_email(user.email, "You can login now!") Account.objects.create(user=user, balance=0) # rest of user creation proccess
    • Альтернатив хувилбарууд
      • Гүйлгээг буцаан дуудах үед зайлшгүй шаардлагатай бизнесийн логикийг хий. Гүйлгээ амжилттай болсны дараа гүйлгээний буцаан дуудлагыг ҮРГЭЛЖ дууддаг бөгөөд гүйлгээний бүх шинэчлэлтүүд нь oncommit-д байдаг.
      • Бид мөн үйлдлийг буцаах боломжтой болгож, өөрөөр хэлбэл үйл явдлыг устгах эсвэл буцаах API дуудлагыг илгээх аргыг бий болгож чадна — Энэ нь үйл явдлын дараалал эсвэл API-г эзэмшдэг багийн хувьд чухал биш ажил юм. Би үүнийг зөвлөхгүй байна.
 def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess # the transaction is still in progress, so it can still be rolled back, it is not # committed until the transaction block is exited, so putting the notification here # is not a good idea - especially if the job starts immediately tries to read the data # this creates a race condition async_notification_service.send_email(user.email, "You can login now!") def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess transaction.on_commit(partial(async_notification_service.send_email, user.email, "You can login now!"))


  • Дуудлага хаах — Гүйлгээ нь өөрчлөгдөж буй хүснэгт/мөрүүд дээр бусад бүх асуулгад ажиллахаас сэргийлдэг тул гүйлгээний үргэлжлэх хугацааг уртасгах аливаа код нь DB-г түгжихэд хүргэж, DB-ээс хамааралтай аппликешнүүдэд хугацаа хэтрүүлж, хариу өгөхгүй болно.


    • Жишээ
      • Сүлжээний дуудлага - Гүйлгээнд оруулах өгөгдлийг авахын тулд API руу хүсэлт илгээх.
      • Бүртгэл нь үүнд хамаарна — Бидний ашигладаг бүртгэл хөтлөгчөөс хамааран номын сан биднийг гүйлгээ хийж байх үед логуудыг илгээж болох юм уу, эсвэл хэрэв бид datadog ашиглаж байгаа бол бүртгэлийг хадгалах өөр процесстой байх боловч багц ажил файлд хадгалах хүртэл бүртгэлийг санах ойд хадгалсны төлбөрийг төлдөг.
      • Дискний үйлдлүүд — Хүснэгтэнд оруулахын тулд CSV ачаалах эсвэл хүснэгтийг CSV руу экспортлох.
      • Процессорын хүнд даалгаврууд — Матрицын үржүүлэх эсвэл аливаа хүнд математик/өгөгдлийн хувиргалт нь CPU болон бусад бүх үйлдлүүдийг блоклох болно — Python-ийн Global Interpreter Lock нь хэлхээ бүрийг CPU-г нэг нэгээр нь ашиглахыг албаддаг бөгөөд Django нь нэг боловсруулалттай байдаг (гүйлгээний үйл ажиллагаа бүр цуваа явагддаг).
     def transaction(user_data, user_files): with transaction.atomic(): user = User.objects.create(**user_data) for file_data in user_files: # transaction waits for this upload and so do all other connections that need access to table/rows the transaction # uses url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url) Account.objects.create(user=user, balance=0) # rest of user creation proccess
    • Альтернатив хувилбарууд
      • Гүйлгээ хийхээс өмнө өгөгдлийг бэлэн болго - Диск/сүлжээний өгөгдлийг урьдчилан ачаална уу. Өгөгдөл бэлэн болмогц түүнтэй гүйлгээг хийнэ үү.
      • Орлуулагчийн өгөгдлийг ашиглах — Амархан олж авах, таних боломжтой, тодорхой орлуулагчийн өгөгдлийн багц (үйлдвэрлэлийн мэдээлэл гэж андуурч болохгүй) үүсгэ. Гүйлгээ хийхээс өмнө ачаалаад ашиглаарай.
      • Өгөгдөл үүсгэх — Хэрэв орлуулагчийн өгөгдлийг ашиглахад саад болох талбарт өвөрмөц байдлын хязгаарлалт байгаа бол.
      • Энэ нь эрсдэлтэй - Энэ нь псевдо санамсаргүй алгоритмын шинж чанараас болж урьдчилан таамаглах боломжгүй бүтэлгүйтэлд хүргэх болно - тиймээс гэнэтийн бүтэлгүйтлээс зайлсхийхийн тулд сайн үртэй санамсаргүй сайн алгоритмыг ашигла.
      • Хязгаарлалтуудыг арилгах эсвэл өөрчлөх - Хэрэв хязгаарлалтууд нь бидний бүртгэлийг аюулгүйгээр үүсгэхийг зөвшөөрөхгүй бол манай схемд асуудал байна. Хязгаарлалтуудыг бүртгэл хэзээ дуусах, хянах ёстойг заасан төлөвийн баганаас хамааралтай болгоно.
 # not bad def transaction(user_data, user_files): user = None with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess for file_data in user_files: url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url) # best fix from functools import partial def transaction(user_data, user_files): user = None with transaction.atomic(): user = User.objects.create(**user_data) Account.objects.create(user=user, balance=0) # rest of user creation proccess # partials create a callable with the function and arguments # so that the function is called with the arguments when the transaction is committed # TODO: diff between partial and lambda here??? transaction.on_commit(partial(create_user_files, user_files, user)) def create_user_files(user_files, user): for file_data in user_files: url = Cloudinary.upload_file(file_data['data']) Files.objects.create(**file_data['meta_data'], user=user, url=url)


Дараа нь - PSQL командууд бие биенээ хэрхэн блоклодог

Дараагийн нийтлэлд бид PSQL-д шумбаж, дараахь зүйлийг олж мэдэх болно.

  • Өөр өөр тушаалууд хүснэгт болон мөрүүдийг хэрхэн түгжих вэ
  • Ямар тушаалуудыг гүйцэтгэх нь хамгийн эрсдэлтэй байдаг

Эх сурвалжууд

  • Атом
  • Django Migrations & Transactions
    • DDL гүйлгээг (SQLite болон PostgreSQL) дэмждэг өгөгдлийн сангууд дээр бүх шилжих үйлдлүүд нь анхдагчаар нэг гүйлгээний дотор ажиллана. Үүний эсрэгээр, хэрэв мэдээллийн сан DDL гүйлгээг (жишээ нь MySQL, Oracle) дэмждэггүй бол бүх үйлдлүүд гүйлгээгүйгээр ажиллах болно.
    • Та атомын атрибутыг Худал болгож тохируулснаар гүйлгээнд шилжихээс сэргийлж чадна. Жишээ нь:
    • Мөн atomic() эсвэл atomic=True-г RunPython руу дамжуулснаар гүйлгээний зарим хэсгийг гүйцэтгэх боломжтой.
  • PSQL хуваалтууд ба Django
    • Django-ийн ORM нь хуваалттай хүснэгтүүдийг дэмждэггүй тул хэрэв та програмдаа хуваалтуудыг ашиглахыг хүсвэл бага зэрэг нэмэлт ажил хийх болно.
    • Хуваалтуудыг ашиглах нэг арга бол түүхий SQL ажиллуулдаг өөрийн шилжилт хөдөлгөөнийг хийх явдал юм. Энэ нь ажиллах болно, гэхдээ энэ нь та ирээдүйд хүснэгтэд хийх бүх өөрчлөлтийн шилжилтийг гараар удирдах шаардлагатай болно гэсэн үг юм.
    • Өөр нэг сонголт бол django-postgres-extra гэсэн багцыг ашиглах явдал юм. Django-postgres-extra нь Django-н ORM-д суулгаагүй хэд хэдэн PostgreSQL функцуудад дэмжлэг үзүүлдэг, тухайлбал TRUNCATE TABLE болон хүснэгт хуваалтыг дэмждэг.
  • PSQL гүйлгээ
  • Python: Django гүйлгээ хэрхэн ажилладаг


L O A D I N G
. . . comments & more!

About Author

Michael T. Andemeskel HackerNoon profile picture
Michael T. Andemeskel@mta
I write code and, occasionally, bad poetry. Thankfully, my code isn’t as bad as my poetry.

TAG ҮҮ

ЭНЭ ӨГҮҮЛЛИЙГ ТОЛГОЙЛУУЛСАН...