خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

API های جنگو را به روشی آسان با قالب های جنگو مصرف کنید

می‌توانید بدون هیچ زحمتی APIهای ساده را بدون نیاز به پیکربندی یک ظاهر خارجی مصرف کنید. با نحوه استفاده از قالب های جنگو برای مصرف API آشنا شوید.

هنگام استفاده از فناوری یا فریم ورک باطنی مانند Django، Laravel، یا Node.js برای نوشتن API های REST، باید با استفاده از فریم ورک هایی مانند React، Angular و Vue برای مصرف نقاط پایانی API، یک مهارت frontend اضافی داشته باشید. اما همیشه اینطور نیست، شما می توانید API ها را در خود جنگو با استفاده از قالب های جنگو مصرف کنید.

راه اندازی یک پروژه جنگو و نقاط پایانی API

اولین قدم ایجاد دایرکتوری پروژه خواهد بود. ترمینال خود را باز کنید و یک دایرکتوری برای پروژه خود ایجاد کنید.

mkdir payment_wallet_project
cd payment_wallet_project

برای این آموزش، APIهایی برای کیف پول پرداخت خواهید ساخت.

کد منبع کامل در یک مخزن GitHub موجود است.

با ایجاد یک محیط مجازی شروع کنید. در این صورت از کتابخانه Pipenv استفاده خواهید کرد.

pipenv install django djangorestframework

این دستور کتابخانه های لازم را نصب می کند و همچنین یک محیط مجازی ایجاد می کند.

با استفاده از دستور زیر محیط مجازی را فعال کنید:

pipenv shell

یک پروژه جنگو جدید به نام PayApp ایجاد کنید.

django-admin startproject PayApp .

استفاده از نقطه (.) در انتهای دستور django-admin تضمین می کند که پروژه از ایجاد دایرکتوری تکراری دایرکتوری پروژه جلوگیری می کند.

یک برنامه جنگو جدید در فهرست پروژه ایجاد کنید.

python manage.py startapp wallet

اکنون با استفاده از مراحل زیر اقدام به ساخت اپلیکیشن API خود کنید.

ایجاد یک Payment Wallet REST API

فایل wallet/models.py را باز کنید و مدل های کیف پول و تراکنش را تعریف کنید.

from django.db import models

class Wallet(models.Model):
   user = models.CharField(max_length=100)
   balance = models.DecimalField(max_digits=10, decimal_places=2)
   date_created = models.DateTimeField(auto_now_add=True)
   date_modified = models.DateTimeField(auto_now=True)

   def __str__(self):
       return self.user

class Transaction(models.Model):
   wallet = models.ForeignKey(Wallet, on_delete=models.CASCADE)
   amount = models.DecimalField(max_digits=10, decimal_places=2)
   timestamp = models.DateTimeField(auto_now_add=True)

در دایرکتوری کیف پول، یک فایل جدید serializers.py ایجاد کنید و سریال سازهای مدل کیف پول و تراکنش را بنویسید.

from rest_framework import serializers
from .models import Wallet, Transaction

class WalletSerializer(serializers.ModelSerializer):
   class Meta:
       model = Wallet
       fields = '__all__'
class TransactionSerializer(serializers.ModelSerializer):
   class Meta:
       model = Transaction
       fields = '__all__'

سریال سازها تمام فیلدها را در مدل های کیف پول و تراکنش در نظر می گیرند.

در wallet/views.py، نماها را برای مدیریت منطق اجرای عملکرد کیف پول بنویسید. این شامل توانایی های واریز و برداشت می شود.

from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.decorators import action
from decimal import Decimal
from .models import Wallet, Transaction
from .serializers import WalletSerializer, TransactionSerializer

class WalletViewSet(viewsets.ModelViewSet):
   queryset = Wallet.objects.all()
   serializer_class = WalletSerializer

@action(detail=True, methods=['post'])
   def deposit(self, request, pk=None):
       wallet = self.get_object()
       amount = Decimal(request.data['amount'])
       wallet.balance += amount
       wallet.save()
       serializer = WalletSerializer(wallet)
       return Response(serializer.data)
      

@action(detail=True, methods=['post'])
   def withdraw(self, request, pk=None):
       wallet = self.get_object()
       amount = Decimal(request.data['amount'])
       if wallet.balance < amount:
           return Response({'error': 'Insufficient funds'},
                           status=status.HTTP_400_BAD_REQUEST)
       wallet.balance -= amount
       wallet.save()
       serializer = WalletSerializer(wallet)
       return Response(serializer.data)'

class TransactionViewSet(viewsets.ModelViewSet):
   queryset = Transaction.objects.all()
   Serializer_class = TransactionSerializer

سپس، مسیریابی URL را برای API با ایجاد یک فایل wallet/urls.py تعریف کنید:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import WalletViewSet, TransactionViewSet, wallet_view

router = DefaultRouter()
router.register(r'wallets', WalletViewSet, basename='wallets')
router.register(r'transactions', TransactionViewSet, basename='transactions')

urlpatterns = [
   path('api/', include(router.urls)),
   path('wallets/<int:pk>/deposit/', WalletViewSet.as_view({'post': 'deposit'}),
        name='wallet-deposit'),
   path('wallets/<int:pk>/withdraw/', WalletViewSet.as_view({'post': 'withdraw'}),
        name='wallet-withdraw'),

]

در urls.py پروژه خود، نشانی‌های اینترنتی برنامه را وارد کنید:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
   path('admin/', admin.site.urls),
   path('', include('wallet.urls')),
]

در فایل PayApp/settings.py، کیف پول و برنامه های rest_framwork را به لیست INSTALLED_APPS اضافه کنید.

INSTALLED_APPS = [

"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",

"rest_framework", # new
"wallet", # new

]

با این کار کیف پول و برنامه های rest_framework در برنامه پروژه جنگو ثبت می شود.

مطلب مرتبط:   5 آموزش رایگان استثنایی برای یادگیری توسعه بدون کد

مصرف API با قالب های جنگو

اکنون، از قالب‌های جنگو برای ایجاد یک ظاهر ساده برای مصرف API استفاده خواهید کرد. یک فایل wallet.html در پوشه wallet/templates/ ایجاد کنید و کد HTML زیر را اضافه کنید.

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <title>Wallet</title>
   <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/
   css/bootstrap.min.css">
</head>
<body>
   <div class="container">
       <h1>Wallets</h1>
       <table class="table">
           <thead>
               <tr>
                   <th>User</th>
                   <th>Balance</th>
                   <th>Actions</th>
               </tr>
           </thead>
           <tbody>
               <tr>
                   <td>{{ wallet.user }}</td>
                   <td id="balance">{{ wallet.balance }}</td>
                   <td>
                       <div id="loading-indicator" class="d-none">
                           <div class="spinner-border text-primary" role="status">
                               <span class="sr-only">Loading...</span>
                           </div>
                           <p>Please wait while the deposit is being processed.</p>
                       </div>
                       <form id="deposit-form" method="post">
                           {% csrf_token %}
                           <input type="number" name="amount" step="0.01" min="0" required>
                           <button type="submit" class="btn btn-success">Deposit</button>
                       </form>
                       <form method="post" id="withdraw-form">
                           {% csrf_token %}
                           <input type="number" name="amount" step="0.01" min="0" required>
                           <button type="submit" class="btn btn-danger">Withdraw</button>
                       </form>
                   </td>
               </tr>
           </tbody>
       </table>
   </div>

</body>
</html>

فایل HTML APIهای واریز و برداشت را در یک رابط کاربری زیبا که با استفاده از Bootstrap طراحی شده است، ارائه می کند.

تعامل کاربر با فرم ها

در فایل HTML یک تگ اسکریپت ایجاد کنید و کد زیر را به شنونده رویداد ارسال فرم واریز اضافه کنید.

<script>
document.querySelector('#deposit-form').addEventListener('submit', function (event) {
           event.preventDefault();
           document.querySelector('#loading-indicator').classList.remove('d-none');
           const amount = parseFloat(document.querySelector("#deposit-form " +
               "input[name='amount']").value);
           fetch("{% url 'wallet-deposit' wallet.id %}", {
               method: "POST",
               headers: {
                   "Content-Type": "application/json",
                   "X-CSRFToken": getCookie("csrftoken")
               },
               body: JSON.stringify({ amount: amount })
           })
               .then(response => response.json())
               .then(data => {
                   console.log(data);
                   if (data.balance !== undefined) {
                       // Convert to number and format
                       const newBalance = parseFloat(data.balance).toFixed(2);
                       document.querySelector("#balance").textContent = newBalance;
                       document.querySelector('#loading-indicator').classList.
                       add('d-none');
                   }
               })
               .catch(error => {
                   console.error("Error:", error);
                   document.querySelector('#loading-indicator')
                       .classList.add('d-none');
               });
       });
</script>

سپس شنونده رویداد را برای ارسال فرم انصراف با استفاده از کد زیر اضافه کنید:

<script>
document.querySelector('#withdraw-form').addEventListener('submit', function (event) {
   event.preventDefault();
   document.querySelector('#loading-indicator').classList.remove('d-none');
   const amount = parseFloat(document.querySelector("#withdraw-form " +
       "input[name='amount']").value);
   fetch("{% url 'wallet-withdraw' wallet.id %}", {
       method: "POST",
       headers: {
           "Content-Type": "application/json",
           "X-CSRFToken": getCookie("csrftoken")
       },
       body: JSON.stringify({ amount: amount })
   })
       .then(response => response.json())
       .then(data => {
           console.log(data);
           if (data.balance !== undefined) { // Change to 'balance' for withdrawal
               const newBalance = parseFloat(data.balance).toFixed(2);
               document.querySelector("#balance").textContent = newBalance;
               document.querySelector('#loading-indicator').classList.add('d-none');
           }
       })
       .catch(error => {
           console.error("Error:", error);
           document.querySelector('#loading-indicator').classList.add('d-none');
       });
});
</script>

شنونده رویداد مسئولیت رسیدگی به واریز و برداشت (#فرم سپرده و #فرم برداشت) را بر عهده دارد.

مطلب مرتبط:   نحوه خراش دادن تصاویر از وب در پایتون

نشانی اینترنتی درخواست واکشی برای تطبیق آدرس‌های اینترنتی برای اقدامات واریز و برداشت است.

سپس پاسخ‌های JSON برای واریزها و برداشت‌ها برای دریافت موجودی به‌روز شده (data.balance) تجزیه می‌شوند. سپس فرمت می شوند و در صفحه نمایش داده می شوند.

سپس، در wallet/views.py، به‌روزرسانی زیر را برای رندر کردن صفحه wallet.html اضافه کنید:

from django.shortcuts import render

def wallet_view(request):
   # Retrieve the wallet to display
   wallet = Wallet.objects.first()
   return render(request, 'wallet.html', {'wallet': wallet})

در این مثال، شما از متد پرس و جو first() برای انتخاب کیف پول یک کاربر برای اهداف نمایشی استفاده خواهید کرد.

فایل urls.py را با افزودن مسیری به wallet_view به صورت زیر به روز کنید:

from .views import wallet_view

urlpatterns = [
   ...
     path('home/', wallet_view, name='wallet-page'),
]

از آدرس اینترنتی http://127.0.0.1:8000/home/ به صفحه کیف پول دسترسی پیدا کنید.

با تنظیم و کار کردن همه چیز مطابق انتظار، دستورات makemigrations و migrate را اجرا کنید. در نهایت برنامه را اجرا کنید:

python manage.py makemigrations
python manage.py migrate

python manage.py runserver

برای دسترسی به نقاط پایانی API، به http://127.0.0.1:8000/api/ بروید.

خروجی مورد انتظار:

نقطه پایانی Wallet API

برای تعامل با کیف پول به لوکال هاست بروید.

خروجی مورد انتظار:

برنامه کیف پول جنگو از طریق لوکال هاست در مرورگر وب قابل دسترسی است

کیف پول موجودی را نشان می دهد و به شما امکان واریز یا برداشت را می دهد.

آشنایی با الگوهای جنگو و نقش آنها در مصرف API

با وجود عالی بودن برای ارائه محتوای ایستا، الگوهای جنگو هنگام استفاده از API دارای محدودیت‌های خاصی هستند:

  • انعطاف پذیری محدود: قالب های جنگو نسبت به قالب هایی که با استفاده از Jinja2 یا Twig ایجاد شده اند انعطاف پذیری کمتری دارند زیرا برای نمایش ساختارهای مشخص استفاده می شوند. به عنوان مثال، در صورت نیاز به مصرف API که داده های JSON را برمی گرداند، باید به صورت دستی JSON را تجزیه کرده و داده ها را در قالب وارد کنید. این می تواند چالش برانگیز باشد، عمدتاً اگر API ساختارهای داده پیچیده ای را ارائه دهد.
  • عدم پشتیبانی از درخواست‌های ناهمزمان: قالب‌های جنگو به طور طبیعی توانایی رسیدگی به درخواست‌های ناهمزمان را ندارند. الگوها همچنان به پردازش همزمان نیاز دارند حتی اگر چارچوب‌های وب معاصر async/wait مانند Flask و Django از نحو پشتیبانی می‌کنند. این بدان معنی است که اگر قبل از رندر کردن صفحه نیاز به دریافت داده از منابع متعدد داشتید، باید قبل از تولید الگو منتظر بمانید تا تمام درخواست‌ها تمام شوند.
  • مدیریت خطای محدود: هنگام استفاده از API ممکن است به طور مرتب خطاها رخ دهد. هیچ مکانیزم داخلی برای رسیدگی به خطاها در قالب‌های جنگو وجود ندارد. اگر فراخوانی API ناموفق باشد، باید استثنا را بگیرید و آن را در خود الگو مدیریت کنید، که می‌تواند منجر به ایجاد کد ناشیانه و چالش برانگیز برای حفظ شود.
مطلب مرتبط:   چگونه دکمه های اشتراک گذاری اجتماعی را به برنامه React خود اضافه کنید

ساخت اپلیکیشن های مقیاس پذیر

با ارائه راهی برای جداسازی لایه ارائه از منطق تجاری، قالب های جنگو به توسعه دهندگان این امکان را می دهد تا روی ایجاد کد قابل استفاده مجدد و قابل نگهداری تمرکز کنند. با این حال، به دلیل محدودیت‌هایی که دارند، قالب‌های جنگو ممکن است بهترین انتخاب در هنگام مصرف API در مقیاس نباشند. فریم ورک های کلاینت مانند React هنوز در ساخت برنامه های مقیاس پذیر مفید هستند.