نحوه ساخت یک برنامه وب مدرن برای مدیریت اطلاعات مشتری با جنگو و واکنش در اوبونتو 18.04

مقدمه

مردم از انواع مختلفی از دستگاه ها برای اتصال به اینترنت و مرور وب استفاده می کنند. به همین دلیل، برنامه ها باید از مکان های مختلف قابل دسترسی باشند. برای وب سایت های سنتی، داشتن یک رابط کاربری واکنش گرا معمولاً کافی است، اما برنامه های پیچیده تر اغلب نیاز به استفاده از تکنیک ها و معماری های دیگر دارند. اینها شامل داشتن برنامه های REST back-end و front-end جداگانه است که می توانند به عنوان برنامه های وب سمت مشتری، برنامه های وب پیشرو (PWA) یا برنامه های تلفن همراه بومی اجرا شوند.

برخی از ابزارهایی که می توانید هنگام ساخت برنامه های پیچیده تر استفاده کنید عبارتند از:

  • React، یک چارچوب جاوا اسکریپت است که به توسعه دهندگان این امکان را می دهد تا برای پشتیبان های REST API خود، صفحات وب و بومی بسازند.
  • جنگو، یک چارچوب وب رایگان و منبع باز پایتون است که از الگوی معماری نرم افزار کنترلر نمای مدل (MVC) پیروی می کند.
  • چارچوب Django REST، یک جعبه ابزار قدرتمند و انعطاف پذیر برای ساخت API های REST در جنگو.

در این آموزش، شما با استفاده از React، Django و Django REST Framework، یک برنامه وب مدرن با پشتوانه و فرانت اند جداگانه REST API خواهید ساخت. با استفاده از React with Django، می‌توانید از آخرین پیشرفت‌های جاوا اسکریپت و توسعه front-end بهره ببرید. به جای ساختن یک برنامه جنگو که از موتور قالب داخلی استفاده می کند، از React به عنوان یک کتابخانه UI استفاده خواهید کرد که از مدل مجازی شی سند (DOM)، رویکرد اعلانی و مؤلفه هایی که به سرعت تغییرات در داده ها را ارائه می دهند، استفاده می کنید.

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

پیش نیازها

برای تکمیل این آموزش، شما نیاز دارید:

  • یک ماشین توسعه با اوبونتو 18.04.
  • پایتون 3، پیپ و venv با دنبال کردن مراحل 1 و 2 نحوه نصب پایتون 3 و راه اندازی یک محیط برنامه نویسی محلی در اوبونتو 18.04 روی دستگاه شما نصب شده است.
  • Node.js 6+ و npm 5.2 یا بالاتر روی دستگاه شما نصب شده است. می توانید هر دوی آنها را با دنبال کردن دستورالعمل های نحوه نصب Node.js در اوبونتو 18.04 در نصب از PPA نصب کنید.

مرحله 1 – ایجاد یک محیط مجازی پایتون و نصب وابستگی ها

در این مرحله، ما یک محیط مجازی ایجاد می کنیم و وابستگی های مورد نیاز را برای برنامه خود نصب می کنیم، از جمله جنگو، فریم ورک Django REST و Django-cors-headers.

برنامه ما از دو سرور توسعه مختلف برای Django و React استفاده خواهد کرد. آنها بر روی پورت های مختلف اجرا می شوند و به عنوان دو دامنه جداگانه عمل می کنند. به همین دلیل، ما باید اشتراک‌گذاری منابع متقاطع (CORS) را برای ارسال درخواست‌های HTTP از React به جنگو بدون مسدود شدن توسط مرورگر فعال کنیم.

به فهرست اصلی خود بروید و با استفاده از ماژول venv Python 3 یک محیط مجازی ایجاد کنید:

cd ~
python3 -m venv ./env

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

source env/bin/activate

بعد، وابستگی های پروژه را با pip نصب کنید. این موارد شامل موارد زیر خواهد بود:

  • جنگو: چارچوب وب برای پروژه.
  • چارچوب Django REST: یک برنامه شخص ثالث که API های REST را با جنگو می سازد.
  • django-cors-headers: بسته ای که CORS را فعال می کند.

فریم ورک جنگو را نصب کنید:

pip install django djangorestframework django-cors-headers

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

مرحله 2 – ایجاد پروژه جنگو

در این مرحله، پروژه جنگو را با استفاده از دستورات و ابزارهای زیر تولید می کنیم:

django-admin startproject-name: django-admin یک ابزار خط فرمان است که برای انجام وظایف با جنگو استفاده می شود. دستور startproject یک پروژه جنگو جدید ایجاد می کند.

python manager.py startapp myapp: manager.py یک اسکریپت کاربردی است که به طور خودکار به هر پروژه جنگو اضافه می شود و تعدادی از وظایف اداری را انجام می دهد: ایجاد برنامه های جدید، انتقال پایگاه داده و ارائه پروژه جنگو به صورت محلی. دستور startapp آن یک برنامه جنگو را در داخل پروژه جنگو ایجاد می کند. در جنگو، اصطلاح اپلیکیشن یک بسته پایتون را توصیف می‌کند که مجموعه‌ای از ویژگی‌ها را در یک پروژه فراهم می‌کند.

برای شروع، پروژه جنگو را با django-admin startproject ایجاد کنید. ما پروژه خود را djangoreactproject می نامیم:

django-admin startproject djangoreactproject

قبل از حرکت، اجازه دهید به ساختار دایرکتوری پروژه جنگو با استفاده از دستور درخت نگاه کنیم.

به پوشه djangoreactproject در ریشه پروژه خود بروید و دستور درخت را اجرا کنید:

cd ~/djangoreactproject
tree

خروجی زیر را خواهید دید:

Output
├── djangoreactproject
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py

پوشه ~/djangoreactproject ریشه پروژه است. در این پوشه، چندین فایل وجود دارد که برای کار شما مهم هستند:

  • manager.py: اسکریپت ابزاری که تعدادی کار اداری را انجام می دهد.
  • settings.py: فایل پیکربندی اصلی پروژه جنگو که در آن می توانید تنظیمات پروژه را تغییر دهید. این تنظیمات شامل متغیرهایی مانند INSTALLED_APPS، لیستی از رشته‌هایی است که برنامه‌های فعال را برای پروژه شما تعیین می‌کنند. اسناد جنگو اطلاعات بیشتری در مورد تنظیمات موجود دارد.
  • urls.py: این فایل حاوی لیستی از الگوهای URL و نماهای مرتبط است. هر الگو ارتباطی بین URL و تابعی که باید برای آن URL فراخوانی شود را ترسیم می کند. برای اطلاعات بیشتر در مورد URL ها و نماها، لطفاً به آموزش ما در مورد نحوه ایجاد نماهای جنگو مراجعه کنید.

اولین قدم ما در کار با پروژه، پیکربندی بسته هایی است که در مرحله قبل نصب کردیم، از جمله چارچوب Django REST و بسته Django CORS، با افزودن آنها به settings.py. فایل را با نانو یا ویرایشگر مورد علاقه خود باز کنید:

nano ~/djangoreactproject/djangoreactproject/settings.py

به تنظیمات INSTALLED_APPS بروید و برنامه های rest_framework و corsheaders را به انتهای لیست اضافه کنید:

...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders'
]

سپس، میان‌افزار corsheaders.middleware.CorsMiddleware را از بسته CORS که قبلاً نصب شده است، به تنظیمات MIDDLEWARE اضافه کنید. این تنظیم لیستی از میان افزارها است، یک کلاس پایتون که حاوی کدهایی است که هر بار که برنامه وب شما درخواست یا پاسخی را انجام می دهد پردازش می شود:

...
MIDDLEWARE = [
...
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware'
]

در مرحله بعد، می توانید CORS را فعال کنید. تنظیم CORS_ORIGIN_ALLOW_ALL مشخص می‌کند که آیا می‌خواهید CORS را برای همه دامنه‌ها مجاز کنید یا نه، و CORS_ORIGIN_WHITELIST یک تاپل پایتون است که حاوی URL‌های مجاز است. در مورد ما، چون سرور توسعه React در http://localhost:3000 اجرا خواهد شد، تنظیمات CORS_ORIGIN_ALLOW_ALL = False و CORS_ORIGIN_WHITELIST(‘localhost:3000’,) جدید را به فایل settings.py خود اضافه می کنیم. این تنظیمات را در هر جایی از فایل اضافه کنید:

...
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'localhost:3000',
)
...

می توانید گزینه های پیکربندی بیشتری را در اسناد django-cors-headers بیابید.

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

هنوز در دایرکتوری ~/djangoreactproject، یک برنامه جدید جنگو به نام مشتریان بسازید:

python manage.py startapp customers

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

در مرحله بعد، این برنامه را به لیست برنامه های نصب شده در فایل settings.py پروژه خود اضافه کنید تا جنگو آن را به عنوان بخشی از پروژه تشخیص دهد. تنظیمات.py را دوباره باز کنید:

nano ~/djangoreactproject/djangoreactproject/settings.py

برنامه مشتریان را اضافه کنید:

...
INSTALLED_APPS = [
...
'rest_framework',
'corsheaders',
'customers'
]
...

سپس، پایگاه داده را مهاجرت کرده و سرور توسعه محلی را راه اندازی کنید. مهاجرت ها روش جنگو برای انتشار تغییراتی است که در مدل های خود ایجاد می کنید در طرحواره پایگاه داده شما. این تغییرات می تواند شامل مواردی مانند اضافه کردن یک فیلد یا حذف یک مدل باشد. برای اطلاعات بیشتر در مورد مدل ها و مهاجرت ها، به نحوه ایجاد مدل های جنگو مراجعه کنید.

انتقال پایگاه داده:

python manage.py migrate

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

python manage.py runserver

خروجی مشابه زیر را خواهید دید:

Output
Performing system checks...
System check identified no issues (0 silenced).
October 22, 2018 - 15:14:50
Django version 2.1.2, using settings 'djangoreactproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

برنامه وب شما از http://127.0.0.1:8000 اجرا خواهد شد. اگر در مرورگر وب خود به این آدرس بروید، باید صفحه زیر را ببینید:

در این مرحله، برنامه را در حال اجرا بگذارید و یک ترمینال جدید برای ادامه توسعه پروژه باز کنید.

مرحله 3 – ایجاد React Frontend

در این بخش، ما قصد داریم اپلیکیشن front-end پروژه خود را با استفاده از React ایجاد کنیم.

React یک ابزار رسمی دارد که به شما امکان می دهد بدون نیاز به پیکربندی مستقیم Webpack، پروژه های React را به سرعت تولید کنید. Webpack یک بسته ماژول است که برای بسته بندی دارایی های وب مانند کد جاوا اسکریپت، CSS و تصاویر استفاده می شود. به طور معمول، قبل از اینکه بتوانید از Webpack استفاده کنید، باید گزینه های پیکربندی مختلفی را تنظیم کنید، اما به لطف ابزار Create-react-app، تا زمانی که تصمیم نگیرید به کنترل بیشتری نیاز دارید، مجبور نیستید مستقیماً با Webpack سروکار داشته باشید. برای اجرای Create-react-app می توانید از npx استفاده کنید، ابزاری که باینری های بسته npm را اجرا می کند.

در ترمینال دوم خود، مطمئن شوید که در فهرست پروژه خود هستید:

cd ~/djangoreactproject

با استفاده از create-react-app و npx یک پروژه React به نام frontend ایجاد کنید:

npx create-react-app frontend

بعد، داخل برنامه React خود حرکت کنید و سرور توسعه را راه اندازی کنید:

cd ~/djangoreactproject/frontend
npm start

برنامه شما از http://localhost:3000/ اجرا خواهد شد:

سرور توسعه React را در حال اجرا بگذارید و پنجره ترمینال دیگری را برای ادامه باز کنید.

برای مشاهده ساختار دایرکتوری کل پروژه در این مرحله، به پوشه ریشه بروید و دوباره درخت را اجرا کنید:

cd ~/djangoreactproject
tree

ساختاری مانند این را خواهید دید:

Output
├── customers
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── djangoreactproject
│ ├── __init__.py
│ ├── __pycache__
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── frontend
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── README.md
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── registerServiceWorker.js
│ └── yarn.lock
└── manage.py

برنامه ما از Bootstrap 4 برای استایل دادن به رابط React استفاده می کند، بنابراین ما آن را در فایل frontend/src/App.css قرار می دهیم که تنظیمات CSS ما را مدیریت می کند. فایل را باز کنید:

nano ~/djangoreactproject/frontend/src/App.css

وارد کردن زیر را به ابتدای فایل اضافه کنید. می‌توانید محتوای موجود فایل را حذف کنید، اگرچه این کار لازم نیست:

@import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';

در اینجا، @import یک دستورالعمل CSS است که برای وارد کردن قوانین سبک از سایر شیوه نامه ها استفاده می شود.

اکنون که هر دو برنامه Back-end و Front-end را ایجاد کرده ایم، بیایید مدل Customer و برخی داده های نمایشی را ایجاد کنیم.

مرحله 4 – ایجاد مدل مشتری و داده های اولیه

پس از ایجاد برنامه جنگو و پیش‌فرض React، گام بعدی ما ایجاد مدل مشتری خواهد بود که نشان‌دهنده جدول پایگاه داده‌ای است که اطلاعات مشتریان را در خود نگه می‌دارد. شما به هیچ SQL نیاز ندارید زیرا نقشه‌بردار رابطه‌ای شی جنگو (ORM) عملیات پایگاه داده را با نگاشت کلاس‌ها و متغیرهای پایتون به جداول و ستون‌های SQL انجام می‌دهد. به این ترتیب ORM جنگو تعاملات SQL با پایگاه داده را از طریق یک رابط پایتون خلاصه می کند.

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

cd ~
source env/bin/activate

به دایرکتوری مشتریان بروید و models.py را باز کنید، یک فایل پایتون که مدل های برنامه شما را در خود نگه می دارد:

cd ~/djangoreactproject/customers/
nano models.py

فایل حاوی محتوای زیر خواهد بود:

from django.db import models
# Create your models here.

API مدل مشتری قبلاً به لطف عبارت import import models from django.db در فایل وارد شده است. اکنون کلاس Customer را اضافه خواهید کرد که models.Model را گسترش می دهد. هر مدل در جنگو یک کلاس پایتون است که django.db.models.Model را گسترش می دهد.

مدل مشتری دارای این فیلدهای پایگاه داده خواهد بود:

  • first_name – نام کوچک مشتری.
  • last_name – نام خانوادگی مشتری.
  • EMAIL – آدرس ایمیل مشتری.
  • phone – شماره تلفن مشتری.
  • ADDRESS – آدرس مشتری.
  • DEScription – توصیف مشتری.
  • createAt – تاریخی که مشتری اضافه می شود.

ما همچنین تابع __str__() را اضافه می کنیم که نحوه نمایش مدل را مشخص می کند. در مورد ما، با نام کوچک مشتری خواهد بود. برای اطلاعات بیشتر در مورد ساخت کلاس ها و تعریف اشیا، لطفاً به نحوه ساخت کلاس ها و تعریف اشیاء در پایتون 3 مراجعه کنید.

کد زیر را به فایل اضافه کنید:

from django.db import models
class Customer(models.Model):
first_name = models.CharField("First name", max_length=255)
last_name = models.CharField("Last name", max_length=255)
email = models.EmailField()
phone = models.CharField(max_length=20)
address = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
createdAt = models.DateTimeField("Created At", auto_now_add=True)

def __str__(self):
return self.first_name

در مرحله بعد، پایگاه داده را برای ایجاد جداول پایگاه داده منتقل کنید. دستور makemigrations فایل‌های مهاجرت را ایجاد می‌کند که در آن تغییرات مدل اضافه می‌شود، و migrate تغییرات فایل‌های مهاجرت را به پایگاه داده اعمال می‌کند.

به پوشه ریشه پروژه برگردید:

cd ~/djangoreactproject

برای ایجاد فایل های مهاجرت، موارد زیر را اجرا کنید:

python manage.py makemigrations

خروجی به شکل زیر دریافت خواهید کرد:

Output
customers/migrations/0001_initial.py
- Create model Customer

این تغییرات را در پایگاه داده اعمال کنید:

python manage.py migrate

خروجی ای را مشاهده خواهید کرد که انتقال موفقیت آمیز را نشان می دهد:

Output
Operations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0001_initial... OK

در مرحله بعد، از یک فایل انتقال داده برای ایجاد داده های اولیه مشتری استفاده خواهید کرد. فایل انتقال داده، مهاجرتی است که داده ها را در پایگاه داده اضافه یا تغییر می دهد. یک فایل انتقال داده خالی برای برنامه مشتریان ایجاد کنید:

python manage.py makemigrations --empty --name customers customers

تأیید زیر را با نام فایل مهاجرت خود مشاهده خواهید کرد:

Output
Migrations for 'customers':
customers/migrations/0002_customers.py

توجه داشته باشید که نام فایل مهاجرت شما 0002_customers.py است.

در مرحله بعد، داخل پوشه migrations برنامه مشتریان حرکت کنید:

cd ~/djangoreactproject/customers/migrations

فایل مهاجرت ایجاد شده را باز کنید:

nano 0002_customers.py

این محتوای اولیه فایل است:

from django.db import migrations

class Migration(migrations.Migration):
dependencies = [
('customers', '0001_initial'),
]
operations = [
]

دستور import، Migrations API را وارد می‌کند، یک API جنگو برای ایجاد مهاجرت، از django.db، یک بسته داخلی که شامل کلاس‌هایی برای کار با پایگاه‌های داده است.

کلاس Migration یک کلاس پایتون است که عملیاتی را که هنگام مهاجرت پایگاه داده اجرا می شود را توصیف می کند. این کلاس migrations.Migration را گسترش می دهد و دو لیست دارد:

  • dependencies: شامل مهاجرت های وابسته است.
  • operations: شامل عملیاتی است که با اعمال مهاجرت اجرا می شود.

در مرحله بعد، روشی برای ایجاد داده‌های مشتری آزمایشی اضافه کنید. قبل از تعریف کلاس Migration متد زیر را اضافه کنید:

...
def create_data(apps, schema_editor):
Customer = apps.get_model('customers', 'Customer')
Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
...

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

برای دریافت کلاس Customer، که ایجاد مشتریان جدید را امکان پذیر می کند، از متد get_model() شی apps استفاده می کنیم. شی apps نشان دهنده رجیستری برنامه های نصب شده و مدل های پایگاه داده آنها است.

وقتی از متد RunPython() برای اجرای ()create_data استفاده می کنیم، شی apps ارسال می شود. متد migrations.RunPython() را به لیست عملیات خالی اضافه کنید:

...
operations = [
migrations.RunPython(create_data),
]

RunPython() بخشی از Migrations API است که به شما امکان می دهد کدهای پایتون سفارشی را در یک مهاجرت اجرا کنید. لیست عملیات ما مشخص می کند که این متد زمانی که ما مهاجرت را اعمال می کنیم اجرا می شود.

این هم فایل کامل:

from django.db import migrations

def create_data(apps, schema_editor):
Customer = apps.get_model('customers', 'Customer')
Customer(first_name="Customer 001", last_name="Customer 001", email="[email protected]", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()

class Migration(migrations.Migration):
dependencies = [
('customers', '0001_initial'),
]
operations = [
migrations.RunPython(create_data),
]

برای اطلاعات بیشتر در مورد انتقال داده ها، به مستندات مربوط به انتقال داده ها در جنگو مراجعه کنید

برای انتقال پایگاه داده خود، ابتدا به پوشه اصلی پروژه خود بازگردید:

cd ~/djangoreactproject

پایگاه داده خود را برای ایجاد داده های آزمایشی مهاجرت کنید:

python manage.py migrate

خروجی را خواهید دید که مهاجرت را تأیید می کند:

Output
Operations to perform:
Apply all migrations: admin, auth, contenttypes, customers, sessions
Running migrations:
Applying customers.0002_customers... OK

با ایجاد مدل مشتری و داده‌های نمایشی، می‌توانیم به ساخت REST API برویم.

مرحله 5 – ایجاد REST API

در این مرحله ما REST API را با استفاده از چارچوب Django REST ایجاد می کنیم. ما چندین نمای API مختلف ایجاد خواهیم کرد. نمای API تابعی است که درخواست یا تماس API را مدیریت می کند، در حالی که نقطه پایانی API یک URL منحصر به فرد است که یک نقطه تماس را با سیستم REST نشان می دهد. به عنوان مثال، هنگامی که کاربر یک درخواست GET را به یک نقطه پایانی API ارسال می کند، جنگو تابع مربوطه یا نمای API را برای رسیدگی به درخواست و بازگرداندن نتایج احتمالی فراخوانی می کند.

ما همچنین از سریال سازها استفاده خواهیم کرد. یک سریال‌ساز در چارچوب Django REST به نمونه‌های مدل پیچیده و QuerySets اجازه می‌دهد تا برای مصرف API به فرمت JSON تبدیل شوند. کلاس سریال ساز همچنین می تواند در جهت دیگر کار کند و مکانیسم هایی را برای تجزیه و جداسازی داده ها در مدل های جنگو و مجموعه های Query فراهم می کند.

نقاط پایانی API ما شامل موارد زیر خواهد بود:

  • api/customers: این نقطه پایانی برای ایجاد مشتریان و برگرداندن مجموعه های صفحه بندی شده از مشتریان استفاده می شود.
  • api/customers/<pk>: این نقطه پایانی برای دریافت، به‌روزرسانی و حذف مشتریان تکی با کلید اصلی یا شناسه استفاده می‌شود.

همچنین آدرس‌هایی را در فایل urls.py پروژه برای نقاط پایانی مربوطه ایجاد می‌کنیم (یعنی api/customers و api/customers/<pk>).

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

اضافه کردن کلاس سریال ساز

ایجاد یک کلاس سریال‌ساز برای مدل مشتری ما برای تبدیل نمونه‌های مشتری و QuerySets به و از JSON ضروری است. برای ایجاد کلاس serializer، ابتدا یک فایل serializers.py در داخل برنامه مشتریان ایجاد کنید:

cd ~/djangoreactproject/customers/
nano serializers.py

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

from rest_framework import serializers
from .models import Customer

در مرحله بعد، یک کلاس سریال‌ساز ایجاد کنید که سریال‌سازها را گسترش می‌دهد.ModelSerializer و فیلدهایی را که سریال‌سازی می‌شوند را مشخص می‌کند:

...
class CustomerSerializer(serializers.ModelSerializer):

class Meta:
model = Customer
fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')

کلاس Meta مدل و فیلدهایی را برای سریال سازی مشخص می کند: pk,first_name, last_name, email, phone, address, description.

اینم محتوای کامل فایل:

from rest_framework import serializers
from .models import Customer

class CustomerSerializer(serializers.ModelSerializer):

class Meta:
model = Customer
fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')

اکنون که کلاس سریال ساز خود را ایجاد کرده ایم، می توانیم نماهای API را اضافه کنیم.

افزودن نماهای API

در این بخش، نماهای API را برای برنامه خود ایجاد می کنیم که زمانی که کاربر از نقطه پایانی مربوط به تابع view بازدید می کند، توسط جنگو فراخوانی می شود.

~/djangoreactproject/customers/views.py را باز کنید:

nano ~/djangoreactproject/customers/views.py

موارد موجود را حذف کنید و واردات زیر را اضافه کنید:

from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Customer 
from .serializers import *

ما سریال‌سازی‌ای را که ایجاد کردیم، همراه با مدل مشتری و APIهای چارچوب REST جنگو و جنگو وارد می‌کنیم.

سپس، نمای پردازش درخواست‌های POST و GET HTTP را اضافه کنید:

...
@api_view(['GET', 'POST'])
def customers_list(request):
"""
List customers, or create a new customer.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
customers = Customer.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(customers, 10)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)
serializer = CustomerSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()
return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
elif request.method == 'POST':
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

ابتدا از دکوراتور @api_view([‘GET’, ‘POST’]) برای ایجاد نمای API استفاده می کنیم که بتواند درخواست های GET و POST را بپذیرد. دکوراتور عملکردی است که عملکرد دیگری را بر عهده می گیرد و به صورت پویا آن را گسترش می دهد.

در بدنه متد، از متغیر request.method برای بررسی روش HTTP فعلی استفاده می کنیم و منطق مربوطه را بسته به نوع درخواست اجرا می کنیم:

  • اگر درخواست GET باشد، این روش داده‌ها را با استفاده از Django Paginator صفحه‌بندی می‌کند و صفحه اول داده‌ها را پس از سریال‌سازی، تعداد مشتریان در دسترس، تعداد صفحات موجود و پیوندهای صفحات قبلی و بعدی را برمی‌گرداند. Paginator یک کلاس Django داخلی است که فهرستی از داده ها را در صفحات صفحه بندی می کند و روش هایی برای دسترسی به آیتم های هر صفحه ارائه می دهد.
  • اگر درخواست POST باشد، متد داده‌های مشتری دریافتی را سریال‌سازی می‌کند و سپس متد save() شی سریال‌ساز را فراخوانی می‌کند. سپس یک شی Response، نمونه ای از HttpResponse، با کد وضعیت 201 برمی گرداند. هر نمایه ای که ایجاد می کنید مسئول برگرداندن یک شی HttpResponse است. متد save() داده های سریال شده را در پایگاه داده ذخیره می کند.

برای اطلاعات بیشتر در مورد HttpResponse و view ها، به این بحث در مورد ایجاد توابع view مراجعه کنید.

اکنون نمای API را اضافه کنید که مسئول پردازش درخواست‌های GET، PUT و DELETE برای دریافت، به‌روزرسانی و حذف مشتریان توسط pk (کلید اصلی) است:

...
@api_view(['GET', 'PUT', 'DELETE'])
def customers_detail(request, pk):
"""
Retrieve, update or delete a customer by id/pk.
"""
try:
customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)

if request.method == 'GET':
serializer = CustomerSerializer(customer,context={'request': request})
return Response(serializer.data)

elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

elif request.method == 'DELETE':
customer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

این روش با @api_view ([‘GET’, ‘PUT’, ‘DELETE’]) تزئین شده است تا نشان دهد که یک نمای API است که می‌تواند درخواست‌های GET، PUT و DELETE را بپذیرد.

چک در فیلد request.method روش درخواست را تأیید می کند و بسته به مقدار آن منطق درست را فراخوانی می کند:

  • اگر درخواست GET باشد، داده‌های مشتری سریال‌سازی می‌شوند و با استفاده از یک شی Response ارسال می‌شوند.
  • اگر یک درخواست PUT باشد، این روش یک سریال‌ساز برای داده‌های مشتری جدید ایجاد می‌کند. سپس، متد save() شی سریال ساز ایجاد شده را فراخوانی می کند. در نهایت، یک شی Response را با مشتری به روز شده ارسال می کند.
  • اگر یک درخواست DELETE باشد، متد متد ()delete شی مشتری را فراخوانی می کند تا آن را حذف کند، سپس یک شی Response بدون داده را برمی گرداند.

فایل تکمیل شده به شکل زیر است:

from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Customer
from .serializers import *


@api_view(['GET', 'POST'])
def customers_list(request):
"""
List customers, or create a new customer.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
customers = Customer.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(customers, 5)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)

serializer = CustomerSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()

return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})

elif request.method == 'POST':
serializer = CustomerSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET', 'PUT', 'DELETE'])
def customers_detail(request, pk):
"""
Retrieve, update or delete a customer by id/pk.
"""
try:
customer = Customer.objects.get(pk=pk)
except Customer.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)

if request.method == 'GET':
serializer = CustomerSerializer(customer,context={'request': request})
return Response(serializer.data)

elif request.method == 'PUT':
serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

elif request.method == 'DELETE':
customer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

اکنون می توانیم به ایجاد نقاط پایانی خود ادامه دهیم.

افزودن نقاط پایانی API

اکنون نقاط پایانی API را ایجاد خواهیم کرد: api/customers/، برای پرس و جو و ایجاد مشتریان، و api/customers/<pk>، برای دریافت، به‌روزرسانی یا حذف مشتریان تکی توسط pk آنها.

~/djangoreactproject/djangoreactproject/urls.py را باز کنید:

nano ~/djangoreactproject/djangoreactproject/urls.py

آنچه وجود دارد را رها کنید، اما واردات را به نمای مشتریان در بالای فایل اضافه کنید:

from django.contrib import admin
from django.urls import path
from customers import views
from django.conf.urls import url

سپس، URL های api/customers/ و api/customers/<pk> را به لیست الگوهای url که حاوی URL های برنامه است اضافه کنید:

...

urlpatterns = [
path('admin/', admin.site.urls),
url(r'^api/customers/$', views.customers_list),
url(r'^api/customers/(?P<pk>[0-9]+)$', views.customers_detail),
]

با ایجاد نقاط پایانی REST، بیایید ببینیم چگونه می توانیم آنها را مصرف کنیم.

مرحله 6 – مصرف REST API با Axios

در این مرحله، Axios را نصب می‌کنیم، کلاینت HTTP که برای برقراری تماس‌های API از آن استفاده می‌کنیم. همچنین یک کلاس برای مصرف نقاط پایانی API که ایجاد کرده‌ایم ایجاد می‌کنیم.

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

deactivate

سپس به پوشه frontend خود بروید:

cd ~/djangoreactproject/frontend

نصب axios از npm با استفاده از:

npm install axios --save

گزینه –save وابستگی axios را به فایل package.json برنامه شما اضافه می کند.

در مرحله بعد، یک فایل جاوا اسکریپت به نام CustomersService.js ایجاد کنید که حاوی کد فراخوانی API های REST است. ما این را در پوشه src، جایی که کد برنامه پروژه ما در آن قرار دارد، ایجاد می کنیم:

cd src
nano CustomersService.js

کد زیر را اضافه کنید که حاوی روش هایی برای اتصال به Django REST API است:

import axios from 'axios';
const API_URL = 'http://localhost:8000';

export default class CustomersService{

constructor(){}


getCustomers() {
const url = `${API_URL}/api/customers/`;
return axios.get(url).then(response => response.data);
}
getCustomersByURL(link){
const url = `${API_URL}${link}`;
return axios.get(url).then(response => response.data);
}
getCustomer(pk) {
const url = `${API_URL}/api/customers/${pk}`;
return axios.get(url).then(response => response.data);
}
deleteCustomer(customer){
const url = `${API_URL}/api/customers/${customer.pk}`;
return axios.delete(url);
}
createCustomer(customer){
const url = `${API_URL}/api/customers/`;
return axios.post(url,customer);
}
updateCustomer(customer){
const url = `${API_URL}/api/customers/${customer.pk}`;
return axios.put(url,customer);
}
}

کلاس CustomersService متدهای Axios زیر را فراخوانی می کند:

  • getCustomers(): صفحه اول مشتریان را دریافت می کند.
  • getCustomersByURL(): مشتریان را بر اساس URL دریافت می کند. این باعث می شود تا با عبور دادن لینک هایی مانند /api/customers/?page=2 به صفحات بعدی مشتریان دسترسی پیدا کنید.
  • getCustomer(): مشتری را با کلید اصلی دریافت می کند.
  • createCustomer(): یک مشتری ایجاد می کند.
  • updateCustomer(): یک مشتری را به روز می کند.
  • deleteCustomer(): یک مشتری را حذف می کند.

اکنون می‌توانیم داده‌های API خود را در رابط کاربری React UI با ایجاد یک جزء CustomersList نمایش دهیم.

مرحله 7 – نمایش داده ها از API در برنامه React

در این مرحله، مؤلفه CustomersList React را ایجاد می کنیم. یک جزء React بخشی از رابط کاربری را نشان می دهد. همچنین به شما امکان می دهد UI را به قطعات مستقل و قابل استفاده مجدد تقسیم کنید.

با ایجاد CustomersList.js در frontend/src شروع کنید:

nano ~/djangoreactproject/frontend/src/CustomersList.js

با وارد کردن React و Component برای ایجاد کامپوننت React شروع کنید:

import React, { Component } from 'react';

سپس، ماژول CustomersService را که در مرحله قبل ایجاد کرده‌اید، وارد کرده و نمونه‌سازی کنید، که روش‌هایی را ارائه می‌دهد که با REST API باطن ارتباط برقرار می‌کنند:

...
import CustomersService from './CustomersService';
const customersService = new CustomersService();

سپس، یک مؤلفه CustomersList ایجاد کنید که Component را برای فراخوانی REST API گسترش دهد. یک کامپوننت React باید کلاس Component را گسترش دهد یا زیر کلاس قرار دهد. برای اطلاعات بیشتر در مورد کلاس های E6 و وراثت، لطفاً به آموزش ما در مورد درک کلاس ها در جاوا اسکریپت مراجعه کنید.

کد زیر را برای ایجاد کامپوننت React که react.Component را گسترش می دهد اضافه کنید:

...
class CustomersList extends Component {

constructor(props) {
super(props);
this.state = {
customers: [],
nextPageURL: ''
};
this.nextPage = this.nextPage.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
}
export default CustomersList;

در داخل سازنده، شی state را مقداردهی اولیه می کنیم. این متغیرهای حالت جزء ما را با استفاده از یک آرایه خالی مشتریان نگه می دارد. این آرایه مشتریان و nextPageURL را نگه می‌دارد که URL صفحه بعدی را برای بازیابی از API پشتیبان نگه می‌دارد. ما همچنین متدهای nextPage() و handleDelete() را به این متصل می کنیم تا از طریق کد HTML قابل دسترسی باشند.

در مرحله بعد، متد ()componentDidMount و یک فراخوانی برای getCustomers() در کلاس CustomersList، قبل از بسته شدن بریس فرفری اضافه کنید.

متد ()componentDidMount یک متد چرخه حیات کامپوننت است که هنگام ایجاد کامپوننت و درج آن در DOM فراخوانی می شود. getCustomers() شیء خدمات مشتریان را فراخوانی می کند تا صفحه اول داده و پیوند صفحه بعدی را از باطن جنگو دریافت کند:

...
componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}

اکنون متد handleDelete() را که حذف مشتری را انجام می دهد، در زیر componentDidMount():

...
handleDelete(e,pk){
var self = this;
customersService.deleteCustomer({pk : pk}).then(()=>{
var newArr = self.state.customers.filter(function(obj) {
return obj.pk !== pk;
});
self.setState({customers: newArr})
});
}

متد handleDelete، متد deleteCustomer() را برای حذف مشتری با استفاده از pk (کلید اصلی) فراخوانی می کند. اگر عملیات موفقیت آمیز باشد، آرایه مشتریان برای مشتری حذف شده فیلتر می شود.

در مرحله بعد، یک متد nextPage() اضافه کنید تا داده‌های صفحه بعد را دریافت کنید و پیوند صفحه بعدی را به‌روزرسانی کنید:

...
nextPage(){
var self = this;
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}

متد ()nextPage یک متد getCustomersByURL() را فراخوانی می کند که URL صفحه بعدی را از شی state، this.state.nextPageURL می گیرد و آرایه مشتریان را با داده های برگشتی به روز می کند.

در نهایت، متد render() جزء را اضافه کنید، که جدولی از مشتریان را از حالت جزء ارائه می‌کند:

...
render() {

return (
<div className="customers--list">
<table className="table">
<thead key="thead">
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
<th>Email</th>
<th>Address</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{this.state.customers.map( c =>
<tr key={c.pk}>
<td>{c.pk} </td>
<td>{c.first_name}</td>
<td>{c.last_name}</td>
<td>{c.phone}</td>
<td>{c.email}</td>
<td>{c.address}</td>
<td>{c.description}</td>
<td>
<button onClick={(e)=> this.handleDelete(e,c.pk) }> Delete</button>
<a href={"/customer/" + c.pk}> Update</a>
</td>
</tr>)}
</tbody>
</table>
<button className="btn btn-primary" onClick= { this.nextPage }>Next</button>
</div>
);
}

اینم محتوای کامل فایل:

import React, { Component } from 'react';
import CustomersService from './CustomersService';

const customersService = new CustomersService();

class CustomersList extends Component {

constructor(props) {
super(props);
this.state = {
customers: [],
nextPageURL: ''
};
this.nextPage = this.nextPage.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}

componentDidMount() {
var self = this;
customersService.getCustomers().then(function (result) {
console.log(result);
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
handleDelete(e,pk){
var self = this;
customersService.deleteCustomer({pk : pk}).then(()=>{
var newArr = self.state.customers.filter(function(obj) {
return obj.pk !== pk;
});

self.setState({customers: newArr})
});
}

nextPage(){
var self = this;
console.log(this.state.nextPageURL);
customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
self.setState({ customers: result.data, nextPageURL: result.nextlink})
});
}
render() {

return (
<div className="customers--list">
<table className="table">
<thead key="thead">
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
<th>Email</th>
<th>Address</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{this.state.customers.map( c =>
<tr key={c.pk}>
<td>{c.pk} </td>
<td>{c.first_name}</td>
<td>{c.last_name}</td>
<td>{c.phone}</td>
<td>{c.email}</td>
<td>{c.address}</td>
<td>{c.description}</td>
<td>
<button onClick={(e)=> this.handleDelete(e,c.pk) }> Delete</button>
<a href={"/customer/" + c.pk}> Update</a>
</td>
</tr>)}
</tbody>
</table>
<button className="btn btn-primary" onClick= { this.nextPage }>Next</button>
</div>
);
}
}
export default CustomersList;

اکنون که مؤلفه CustomersList را برای نمایش لیست مشتریان ایجاد کرده‌ایم، می‌توانیم مؤلفه‌ای را اضافه کنیم که ایجاد و به‌روزرسانی مشتری را مدیریت می‌کند.

مرحله 8 – افزودن مؤلفه React Create و به روز رسانی مشتری

در این مرحله، مؤلفه CustomerCreateUpdate را ایجاد می‌کنیم که به ایجاد و به‌روزرسانی مشتریان رسیدگی می‌کند. این کار را با ارائه فرمی انجام می دهد که کاربران می توانند از آن برای وارد کردن داده های مشتری جدید یا به روز رسانی ورودی موجود استفاده کنند.

در frontend/src، یک فایل CustomerCreateUpdate.js ایجاد کنید:

nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

کد زیر را برای ایجاد کامپوننت React با وارد کردن React و Component اضافه کنید:

import React, { Component } from 'react';

همچنین می‌توانیم کلاس CustomersService را که در مرحله قبل ایجاد کرده‌ایم، وارد و نمونه‌سازی کنیم، که روش‌هایی را ارائه می‌دهد که با REST API باطن ارتباط برقرار می‌کنند:

...
import CustomersService from './CustomersService';

const customersService = new CustomersService();

سپس، یک مؤلفه CustomerCreateUpdate ایجاد کنید که Component را برای ایجاد و به‌روزرسانی مشتریان گسترش می‌دهد:

...
class CustomerCreateUpdate extends Component {

constructor(props) {
super(props);
}
}
export default CustomerCreateUpdate;

در تعریف کلاس، متد render() کامپوننت را اضافه کنید که یک فرم HTML را ارائه می‌کند که اطلاعات مشتری را می‌گیرد:

...
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
First Name:</label>
<input className="form-control" type="text" ref='firstName' />

<label>
Last Name:</label>
<input className="form-control" type="text" ref='lastName'/>

<label>
Phone:</label>
<input className="form-control" type="text" ref='phone' />

<label>
Email:</label>
<input className="form-control" type="text" ref='email' />

<label>
Address:</label>
<input className="form-control" type="text" ref='address' />

<label>
Description:</label>
<textarea className="form-control" ref='description' ></textarea>

<input className="btn btn-primary" type="submit" value="Submit" />
</div>
</form>
);
}

برای هر عنصر ورودی فرم، متد یک ویژگی ref را برای دسترسی و تنظیم مقدار عنصر فرم اضافه می کند.

در مرحله بعد، در بالای متد render() یک متد handleSubmit(رویداد) تعریف کنید تا زمانی که کاربر روی دکمه ارسال کلیک می‌کند، عملکرد مناسب را داشته باشید:

...
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}
...

متد handleSubmit(event) ارسال فرم را مدیریت می کند و بسته به مسیر، یا متد handleUpdate(pk) را برای به روز رسانی مشتری با pk پاس شده یا متد handleCreate() را برای ایجاد یک مشتری جدید فراخوانی می کند. به زودی این روش ها را تعریف خواهیم کرد.

برگردید در سازنده کامپوننت، متد ()handleSubmit که به تازگی اضافه شده است را به این پیوند دهید تا بتوانید در فرم خود به آن دسترسی داشته باشید:

...
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
...

سپس متد handleCreate() را برای ایجاد مشتری از داده های فرم تعریف کنید. بالای متد handleSubmit(event) کد زیر را اضافه کنید:

...
handleCreate(){
customersService.createCustomer(
{
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}).then((result)=>{
alert("Customer created!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
...

متد handleCreate() برای ایجاد مشتری از داده های ورودی استفاده می شود. متد مربوطه CustomersService.createCustomer() را فراخوانی می کند که API واقعی را به backend فراخوانی می کند تا مشتری ایجاد کند.

سپس، در زیر متد handleCreate، متد handleUpdate(pk) را برای پیاده‌سازی به‌روزرسانی‌ها تعریف کنید:

...
handleUpdate(pk){
customersService.updateCustomer(
{
"pk": pk,
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
}
).then((result)=>{

alert("Customer updated!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}

متد updateCustomer() یک مشتری را با استفاده از اطلاعات جدید از فرم اطلاعات مشتری به روز می کند. متد customersService.updateCustomer() را فراخوانی می کند.

سپس یک متد ()componentDidMount اضافه کنید. اگر کاربر از مسیر مشتری/:pk بازدید کند، می‌خواهیم با استفاده از کلید اصلی از URL، فرم را با اطلاعات مربوط به مشتری پر کنیم. برای انجام این کار، می‌توانیم متد getCustomer(pk) را بعد از اینکه کامپوننت در رویداد چرخه حیات (lifecycle event) componentDidMount () سوار شد اضافه کنیم. برای اضافه کردن این متد کد زیر را در زیر سازنده کامپوننت اضافه کنید:

...
componentDidMount(){
const { match: { params } } = this.props;
if(params && params.pk)
{
customersService.getCustomer(params.pk).then((c)=>{
this.refs.firstName.value = c.first_name;
this.refs.lastName.value = c.last_name;
this.refs.email.value = c.email;
this.refs.phone.value = c.phone;
this.refs.address.value = c.address;
this.refs.description.value = c.description;
})
}
}

اینم محتوای کامل فایل:

import React, { Component } from 'react';
import CustomersService from './CustomersService';
const customersService = new CustomersService();
class CustomerCreateUpdate extends Component {
constructor(props) {
super(props);

this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount(){
const { match: { params } } = this.props;
if(params && params.pk)
{
customersService.getCustomer(params.pk).then((c)=>{
this.refs.firstName.value = c.first_name;
this.refs.lastName.value = c.last_name;
this.refs.email.value = c.email;
this.refs.phone.value = c.phone;
this.refs.address.value = c.address;
this.refs.description.value = c.description;
})
}
}
handleCreate(){
customersService.createCustomer(
{
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
} 
).then((result)=>{
alert("Customer created!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
handleUpdate(pk){
customersService.updateCustomer(
{
"pk": pk,
"first_name": this.refs.firstName.value,
"last_name": this.refs.lastName.value,
"email": this.refs.email.value,
"phone": this.refs.phone.value,
"address": this.refs.address.value,
"description": this.refs.description.value
} 
).then((result)=>{
console.log(result);
alert("Customer updated!");
}).catch(()=>{
alert('There was an error! Please re-check your form.');
});
}
handleSubmit(event) {
const { match: { params } } = this.props;
if(params && params.pk){
this.handleUpdate(params.pk);
}
else
{
this.handleCreate();
}
event.preventDefault();
}

render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
First Name:</label>
<input className="form-control" type="text" ref='firstName' />

<label>
Last Name:</label>
<input className="form-control" type="text" ref='lastName'/>

<label>
Phone:</label>
<input className="form-control" type="text" ref='phone' />

<label>
Email:</label>
<input className="form-control" type="text" ref='email' />

<label>
Address:</label>
<input className="form-control" type="text" ref='address' />

<label>
Description:</label>
<textarea className="form-control" ref='description' ></textarea>

<input className="btn btn-primary" type="submit" value="Submit" />
</div>
</form>
);
} 
}
export default CustomerCreateUpdate;

با ایجاد مؤلفه CustomerCreateUpdate، می‌توانیم مؤلفه اصلی App را به‌روزرسانی کنیم تا پیوندهایی به مؤلفه‌های مختلفی که ایجاد کرده‌ایم اضافه کنیم.

مرحله 9 – به روز رسانی مؤلفه اصلی برنامه

در این بخش، مؤلفه App برنامه خود را به‌روزرسانی می‌کنیم تا به مؤلفه‌هایی که در مراحل قبلی ایجاد کرده‌ایم پیوند ایجاد کنیم.

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

cd ~/djangoreactproject/frontend
npm install --save react-router-dom

بعد، ~/djangoreactproject/frontend/src/App.js را باز کنید:

nano ~/djangoreactproject/frontend/src/App.js

تمام موارد موجود را حذف کنید و کد زیر را اضافه کنید تا کلاس های لازم برای اضافه کردن مسیریابی را وارد کنید. اینها عبارتند از BrowserRouter که یک جزء Router ایجاد می کند و Route که یک جزء مسیر ایجاد می کند:

import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom'
import { Route, Link } from 'react-router-dom'
import CustomersList from './CustomersList'
import CustomerCreateUpdate from './CustomerCreateUpdate'
import './App.css';

BrowserRouter با استفاده از API تاریخچه HTML5، UI را با URL همگام نگه می دارد.

در مرحله بعد، یک طرح پایه ایجاد کنید که مؤلفه پایه را برای بسته شدن توسط مؤلفه BrowserRouter فراهم می کند:

...
const BaseLayout = () => (
<div className="container-fluid">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Django React Demo</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<a className="nav-item nav-link" href="/">CUSTOMERS</a>
<a className="nav-item nav-link" href="/customer">CREATE CUSTOMER</a>
</div>
</div>
</nav>
<div className="content">
<Route path="/" exact component={CustomersList} />
<Route path="/customer/:pk" component={CustomerCreateUpdate} />
<Route path="/customer/" exact component={CustomerCreateUpdate} />
</div>
</div>
)

ما از مؤلفه Route برای تعریف مسیرهای برنامه خود استفاده می کنیم. کامپوننتی که روتر باید به محض یافتن مطابقت بارگذاری کند. هر مسیر به یک مسیر برای تعیین مسیری که باید مطابقت داده شود و یک مؤلفه برای تعیین مولفه مورد نظر نیاز دارد. ویژگی exact به روتر می گوید که دقیقاً با مسیر مطابقت داشته باشد.

در نهایت، کامپوننت App، مولفه اصلی یا سطح بالای برنامه React ما را ایجاد کنید:

...
class App extends Component {
render() {
return (
<BrowserRouter>
<BaseLayout/>
</BrowserRouter>
);
}
}
export default App;

ما مؤلفه BaseLayout را با مؤلفه BrowserRouter پیچیده‌ایم زیرا برنامه ما قرار است در مرورگر اجرا شود.

فایل تکمیل شده به شکل زیر است:

import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom'
import { Route, Link } from 'react-router-dom'
import CustomersList from './CustomersList'
import CustomerCreateUpdate from './CustomerCreateUpdate'
import './App.css';
const BaseLayout = () => (
<div className="container-fluid">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Django React Demo</a>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<a className="nav-item nav-link" href="/">CUSTOMERS</a>
<a className="nav-item nav-link" href="/customer">CREATE CUSTOMER</a>

</div>
</div>
</nav>
<div className="content">
<Route path="/" exact component={CustomersList} />
<Route path="/customer/:pk" component={CustomerCreateUpdate} />
<Route path="/customer/" exact component={CustomerCreateUpdate} />
</div>
</div>
)
class App extends Component {
render() {
return (
<BrowserRouter>
<BaseLayout/>
</BrowserRouter>
);
}
}
export default App;

پس از افزودن مسیریابی به برنامه خود، اکنون آماده آزمایش برنامه هستیم. به http://localhost:3000 بروید. شما باید صفحه اول برنامه را ببینید:

با وجود این برنامه، اکنون پایه یک برنامه CRM را دارید.

نتیجه

در این آموزش با استفاده از Django و React یک اپلیکیشن دمو ایجاد کردید. شما از چارچوب Django REST برای ساخت REST API، Axios برای مصرف API و Bootstrap 4 برای استایل CSS خود استفاده کردید. کد منبع این پروژه را می توانید در این مخزن GitHub پیدا کنید.

[تعداد: 1   میانگین: 5/5]
دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

شاید دوست داشته باشید