021-71053903 [email protected] پشتیبانی از شنبه تا چهارشنبه ساعت 9 الی 16

ساخت اپلیکیشن CRUD با Django + React

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

خوب داخل این پست می خواهیم چیکار کنیم ؟

هدف پست:

  • ساخت یک برنامه CRUD با جنگو و ری اکت

 

مقدمه

در این مقاله، می خواهیم یک برنامه لیست فیلم ساده CRUD (با قابلیت های ایجاد، خواندن، به‌روزرسانی و یا حذف) را با استفاده از React برای رابط کاربری و جنگو برای بک‌اند آن پیاده‌سازی می‌کنیم. دقیقاً، backend یک REST API خواهد بود که بر روی چارچوب جنگو به نام Django Rest Framework ساخته شده است. با استفاده از API، front-end ما داده ها را واکشی می کنیم و به کاربران نمایش می دهیم، داده ها را به روز می کنیم و سپس داده های موجود را حذف می کنیم.

React.js یک کتابخانه جاوا اسکریپت جلویی است که برای ساخت رابط های کاربری تعاملی برای برنامه ها استفاده می شود. این کتابخانه مبتنی بر مؤلفه است. یعنی رابط های کاربری را با استفاده از مولفه های کلاس یا کامپوننت های مبتنی بر تابع پیاده سازی می کند.

از سوی دیگر، جنگو یک چارچوب باطن منبع باز پایتون است که صرفاً بر اساس معماری Model-view-Template ساخته شده است.

از طرفی برای واکشی داده‌ها از API، از Axios API که node.js است و HTTP Client مرورگر برای بازگرداندن استفاده خواهیم کرد.

 

 

پیش نیازها

  • لازم است که درک اولیه ای از کتابخانه React و مفاهیم جنگو داشته باشید.
  • همچنین، قبل از ادامه باید node.js و Python  و Django و Virtualenv را نصب کرده باشید.

 

پیاده سازی BackEnd

اولی قدمی که باید در راستای انجام این پروژه برداریم ساخت Rest API با جنگو است و با باید کاملا این موضوع را پیاده سازی کنیم که در ادامه بیشتر توضیح خواهیم داد.

 

 

راهنمای محیط توسعه

یک پوشه جدید برای پروژه React و Django ایجاد کنید.

در پوشه ایجاد شده، دستورات زیر را برای ایجاد پوشه پروژه Backend اجرا کنید.

دستورات زیر:

mkdir backend
cd backend

 

راه اندازی محیط مجازی

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

virtualenv env

 

سپس با دستور زیر آن را فعال کنید:

env\Scripts\activate

اگر دستور بالا درست کار نکرد از دستور زیر استفاده کنید(در ویندوز):

env\Scripts\activate

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

 

راه اندازی جنگو

در حالی که هنوز در پوشه قبلی هستید، Django و Django Rest Framework را نصب کنید:

pip install django
pip install djangorestframework

 

از آنجایی که ما درخواست‌هایی را از قسمت Front برنامه خود به API ارسال می‌کنیم، django-cors-header را نیاز داریم که نصب کنیم. این یک برنامه جنگو است که هدرهای سرور را در پاسخ‌های اشتراک‌گذاری منابع متقاطع یعنی (CORS) رسیدگی می‌کند. از این طریق، درخواست‌های سایر منابع از جمله نرم افزار React ما از طریق مرورگر مجاز خواهند بود تا داده ها را پردازش کند.

دستور نصب django-cors-header :

python -m pip install django-cors-headers

 

مرحله بعد، ما یک پروژه جنگو ایجاد می کنیم که نام آن را backend_app می گذاریم و از ابزار داخلی django-admin برای ایجاد آن استفاده می کنیم:

django-admin startproject backend_project .

 

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

python manage.py migrate

 

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

python manage.py startapp backend_api

 

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

# Application definition

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

    #own
    'backend_api',

    #third_party
    'rest_framework',
    'corsheaders',
]

 

در حالی که هنوز در فایل setting.py هستید، این کلاس میان افزار را اضافه کنید که به پاسخ های داده شده گوش می دهد.

نکته*:: این کلاس باید قبل از هر میان افزاری مانند CommonMiddleware جنگو یا WhiteNoiseMiddleware که می تواند پاسخ ایجاد کند، قرار گیرد. اگر کلاس coreheaders بعد از این کلاس‌ها بیاید، سرصفحه‌های CORS به پاسخ‌ها اضافه نمی‌شوند.

 

MIDDLEWARE = [
    . . .,
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    . . .,
    
]

 

در نهایت، پورت React را که از طریق آن درخواست ها ارائه می شود، به CORS_ORIGIN_WHITELIST اضافه کنید.

این قطعه کد باید به فایل backend_project/settings.py اضافه می شود.

CORS_ORIGIN_WHITELIST = [
    'http://localhost:3000',
]

 

ایجاد API

اکنون که تنظیمات اولیه محیط را به طور کامل انجام دادیم، می توانیم شروع به ایجاد API خود کنیم.

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

 

 

ساخت مدل

کد زیر را در فایل backend_api/models.py خود کپی کنید.

from django.db import models

# Create your models here.
class Movie(models.Model):
    name = models.CharField(max_length=250)
    genre = models.CharField(max_length=200)
    starring = models.CharField(max_length=350)

    def __str__(self):
        return self.name

 

مدل فیلم شامل:

  • فیلد نام: نام فیلم هایی که قرار است اضافه کنیم
  • ژانر: طبقه بندی فیلم
  • بازیگران: فیلم با حضور شخصیت ها

برای نمایش ویژگی پیش فرض مدل، از روش __str__ استفاده می شود. در اینجا، فیلد نام برگردانده خواهد شد.

سپس مدل خود را در پایگاه داده ست می کنیم:

python manage.py makemigrations

 

python manage.py migrate

 

ثبت مدل در صفحه مدیریت

باید مدل فیلم را در صفحه مدیریت ثبت کنیم. به این ترتیب، مدیران و کاربران تایید شده مجاز به کار مستقیم با مدل هستند.

کد زیر را در backend_api/admin.py تایپ کنید.

from django.contrib import admin
from .models import Movie
# Register your models here.

class MovieAdmin(admin.ModelAdmin):
    list = ('name', 'genre', 'starring')

    admin.site.register(Movie)

 

کار با Serializers

لازم است مجموعه‌های کوئری پیچیده از پایگاه داده به انواع داده‌های ساده پایتون و بعداً به فرمت‌هایی مانند JSON، XML تبدیل شوند که به راحتی در سمت کاربر ارائه می‌شوند. این فرآیند سریال سازی نامیده می شود و برعکس فرآیندی به نام deserialization نیز انجام می شود.

ما ModelSerializer را پیاده سازی می کنیم که فیلدهای سریال ساز را مستقیماً به فیلدهای مدل نگاشت می کند.

یک فایل serializers.py در پوشه backend_api ایجاد کنید و موارد زیر را کپی کنید.

from rest_framework import serializers
from backend_api.models import Movie

class MovieSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movie
        fields = '__all__'

 

پاس دادن «__all__» به ویژگی فیلدها، هر فیلد را در مدل فیلم ما برمی گرداند.

 

تعریف ViewSets

ViewSet هر منطق نماهای مرتبط را در چارچوب Django Rest ترکیب می کند.

ما ModelViewSet را دقیقا پیاده سازی خواهیم کرد.

این کد را در فایل views.py بنویسید.

from django.shortcuts import render
from .models import Movie
from .serializers import MovieSerializer
from rest_framework import viewsets

# Create your views here.
class MovieViewSet(viewsets.ModelViewSet):
    serializer_class = MovieSerializer
    queryset = Movie.objects.all()

این مجموعه نمایش باید به‌عنوان یک URL ثبت شود که درخواست‌های موجود در View را برمی‌گرداند و آنها را به عنوان یک الگو به مرورگر ارائه می‌کند.

 

هنوز در پوشه backend_api، یک urls.py ایجاد کنید و این کد را در زیر اضافه کنید.

from backend_api.views import MovieViewSet
from rest_framework.routers import DefaultRouter
from backend_api import views

router = DefaultRouter()
router.register(r'movies', views.MovieViewSet, basename='movie')
urlpatterns = router.urls

 

مسیریابی API ما توسط router.urls ارائه خواهد شد. از طریق روتر، می توانیم عملیات CRUD بعدی را ایجاد کنیم.

استفاده از ModelViewSet به‌طور پیش‌فرض، متدهای درخواست HTTP «get()، post()، delete()، put()» را فراهم می‌کند که از طریق آن عملیات CRUD انجام می‌شود.

اکنون باید URL های برنامه را در URL پروژه در backend_project/urls.py قرار دهیم.

 

نقطه پایانی را تعریف کنید که مانند زیر از طریق آن به برنامه backend_api دسترسی پیدا کنیم.

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

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

 

در حال اجرا API

اکنون که بلوک‌های سازنده API اصلی را پیاده‌سازی کرده‌ایم، اجازه دهید سرور محلی را اجرا کرده و داده‌ها را به API وارد کنیم.

python manage.py runserver

 

پس از ارسال داده های API جدید، API مرورگر شما باید به شکل زیر باشد:

 

توجه داشته باشید که از داده‌های API که اضافه می‌کنیم و در اینجا پست می‌کنیم، به زودی عملیات CRUD را انجام خواهیم داد.

اکنون که API خود را کاملاً آماده کرده‌ایم، بیایید اکنون قسمت جلویی را ایجاد کنیم.

 

ایجاد Front برنامه با استفاده از React

برنامه react باید از طریق این دستور نصب شود. جایی که frontend نام برنامه ما است.

npx create-react-app frontend

 

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

cd frontend
npm start

 

به یاد داشته باشید که در مقدمه خود ذکر کردیم که React.js کتابخانه ای است که رابط های کاربری را از طریق کامپوننت ها ایجاد می کند. مبتنی بر تابع یا کلاس محور. این مقاله اجزای عملکردی را پیاده سازی می کند.

برای شروع برنامه، ابتدا از داده های غیر واقعی استفاده می کنیم که در قلاب useState React ذخیره می کنیم. این قلاب به طور کلی وضعیت برنامه را مدیریت می کند. این قلاب ها در اجزای عملکردی بسیار مفید هستند زیرا نیاز به استفاده از اجزای حالت (اجزای کلاس) برطرف می شود.

 

کد موجود در فایل App.js را با کد زیر جایگزین کنید.

import {useState, useEffect} from 'react';
import './App.css';

function App() {

  const [movies, setMovies] = useState([])
  useEffect (() => {
    setMovies([
      {
        name:'Billions',
        genre: 'Drama',
        starring: 'Damian Lewis, Paul Giamatt',
      },
      {
        name:'Sarafina',
        genre: 'drama',
        starring: 'Leleti Khumalo',
      },
    
    ])
  }, [])
  return (
    <div className="App">
      {/* const {movies} = movies */}
      {movies.map((movie, index) => {
        return(
          <div className="movies">
            <h2>{movie.name}</h2>
            <h3>{movie.genre}</h3>
            <h4>{movie.starring}</h4>
          </div>
        )
      }
      )}
    </div>
  );  

export default App;

در کد بالا، useState را مقداردهی اولیه کرده و در یک لیست خالی ارسال کنید. قلاب useEffect لیست تعریف شده از ویژگی های فیلم را هنگامی که مؤلفه بر روی مرورگر نصب می شود، ارائه می دهد. بعداً، داده‌ها را از API که با استفاده از «fetch» API ایجاد کرده‌ایم واکشی خواهیم کرد.

 

حالت فیلم شامل دو شی است که با استفاده از Array.prototype.map در مرورگر نگاشت آنها را چاپ می کنیم. سرور Local به صورت خودکار بارگیری می شود و مرورگر باید اکنون به این شکل باشد.

با استفاده از API Axios

همانطور که قبلا ذکر شد، Axios API در اینجا برای ارسال درخواست به باطن استفاده خواهد شد. قبل از استفاده باید نصب شود.

npm install axios

 

 

برای استایل دادن به برنامه، چارچوب React-Bootstrap را با استفاده از بسته npm نصب و استفاده می کنیم.

npm install react-bootstrap [email protected]

 

این فریم ورک بوت استرپ به برخی کامپوننت ها نیاز دارد. بنابراین، این خط کد را در فایل src/index.js یا App.js خود قرار دهید

import 'bootstrap/dist/css/bootstrap.min.css';

 

ما منطق پیکربندی Axios را در یک فایل کامپوننت جداگانه جدا می کنیم و فقط آن را به جزء برنامه خود وارد می کنیم که نام آن را AddMovie.js می گذاریم. این همیشه یک راه تمیزتر، خوانا و ساده برای اجرای API Axios و کد ما به طور کلی است. بنابراین، یک فایل به نام API.js در دایرکتوری src ایجاد کنید و این کد را اضافه کنید.

import axios from 'axios';

export default axios.create({
    baseURL: "http://127.0.0.1:8000/backend_api/movies",
    headers: {
        'Accept':'application/json',
        'Content-Type':'application/json',
    }
})

 

برای نمادهای حذف و به روز رسانی، از نمادهای فا فا نصب کنید.

npm install –save font-awesome

 

اکنون فایل کامپوننت AddMovie.js را ایجاد کنید که کل منطق CRUD از آن اعمال خواهد شد.

import { useState, useEffect } from "react";
import { ListGroup, Card, Button, Form } from "react-bootstrap";
import API from "./API";

const AddMovie = ({ onAdd }) => {
  const [name, setName] = useState("");
  const [genre, setGenre] = useState("");
  const [starring, setStarring] = useState("");
  const [movieId, setMovieId] = useState(null);
  const [movies, setMovies] = useState([]);

  useEffect(() => {
    refreshMovies();
  }, []);

  const refreshMovies = () => {
    API.get("/")
      .then((res) => {
        setMovies(res.data);
        // setName(res[0].name)
        // setGenre(res[0].genre)
        // setStarring(res[0].starring)
        // setMovieId(res[0].id)
      })
      .catch(console.error);
  };

  const onSubmit = (e) => {
    e.preventDefault();
    let item = { name, genre, starring };
    API.post("/", item).then(() => refreshMovies());
  };

  const onUpdate = (id) => {
    let item = { name };
    API.patch(`/${id}/`, item).then((res) => refreshMovies());
  };

  const onDelete = (id) => {
    API.delete(`/${id}/`).then((res) => refreshMovies());
  };

  function selectMovie(id) {
    let item = movies.filter((movie) => movie.id === id)[0];
    setName(item.name);
    setGenre(item.genre);
    setStarring(item.starring);
    setMovieId(item.id);
  }

  return (
    <div className="container mt-5">
      <div className="row">
        <div className="col-md-4">
          <h3 className="float-left">Create a new Movie</h3>
          <Form onSubmit={onSubmit} className="mt-4">
            <Form.Group className="mb-3" controlId="formBasicName">
              <Form.Label>{movieId}Name</Form.Label>
              <Form.Control
                type="text"
                placeholder="Enter Name"
                value={name}
                onChange={(e) => setName(e.target.value)}
              />
            </Form.Group>

            <Form.Group className="mb-3" controlId="formBasicGenre">
              <Form.Label>Genre</Form.Label>
              <Form.Control
                type="text"
                placeholder="Enter Genre"
                value={genre}
                onChange={(e) => setGenre(e.target.value)}
              />
            </Form.Group>

            <Form.Group className="mb-3" controlId="formBasicStarring">
              <Form.Label>Starring</Form.Label>
              <Form.Control
                type="text"
                placeholder="Enter Starring"
                value={starring}
                onChange={(e) => setStarring(e.target.value)}
              />
            </Form.Group>

            <div className="float-right">
              <Button
                variant="primary"
                type="submit"
                onClick={onSubmit}
                className="mx-2"
              >
                Save
              </Button>
              <Button
                variant="primary"
                type="button"
                onClick={() => onUpdate(movieId)}
                className="mx-2"
              >
                Update
              </Button>
            </div>
          </Form>
        </div>
        <div className="col-md-8 m">
          <table class="table">
            <thead>
              <tr>
                <th scope="col">#</th>
                <th scope="col">Movie Name</th>
                <th scope="col">Genre</th>
                <th scope="col">Starring</th>
                <th scope="col"></th>
              </tr>
            </thead>
            <tbody>
              {movies.map((movie, index) => {
                return (
                  <tr key="">
                    <th scope="row">{movie.id}</th>
                    <td> {movie.name}</td>
                    <td>{movie.genre}</td>
                    <td>{movie.starring}</td>
                    <td>
                      <i
                        className="fa fa-pencil-square text-primary d-inline"
                        aria-hidden="true"
                        onClick={() => selectMovie(movie.id)}
                      ></i>
                      <i
                        className="fa fa-trash-o text-danger d-inline mx-3"
                        aria-hidden="true"
                        onClick={() => onDelete(movie.id)}
                      ></i>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
};

export default AddMovie;

فراموش نکنید که جزء AddMovie.js را به فایل App.js وارد کنید. این تنها راهی است که می توان آن را به مرورگر ارائه کرد.

import './App.css';
import AddMovie from './AddMovie'

function App() {
   
  return (
    <div className="App">
      <AddMovie/>
      
    </div>
  );
}

export default App;

در کد بالا، فیلد فیلم شامل نام، ژانر و قسمت ستاره را تنظیم کرده و در useState ذخیره می کنیم. این hook حالت خالی را مقدار دهی اولیه می کند.

useEffect یک hook است که وقتی کامپوننت روی مرورگر قرار می‌گیرد، مؤلفه را به روشی از پیش تعریف‌شده به مرورگر ارائه می‌کند. در این حالت، کامپوننت داده‌های API را که از backend با استفاده از متد get واکشی شده است، ارائه می‌کند. توجه داشته باشید که ما API را با تنظیمات پیش‌فرض Axios از پیش پیکربندی شده وارد می‌کنیم که در فایل API.js تعریف کرده‌ایم. فراخوانی روش های درخواست HTTP در محتوای API خواناتر است.

 

تابع onSubmit از فرمی که با استفاده از متد ارسال ایجاد شده است، داده های جدیدی را به باطن اضافه می کند. این تابع در دکمه Save با استفاده از روش onClick فراخوانی می شود.

تابع onDelete، همانطور که می توان فرض کرد، بر روی دکمه Delete فراخوانی می شود و با کلیک بر روی این دکمه، یک آیتم داده خاص که توسط یک شناسه خاص به آن ارجاع داده شده است برای همیشه از API حذف می شود. توجه داشته باشید که هر اقدامی که در فرانت‌اند اجرا می‌شود، به‌طور مستقیم بر داده‌های باطن تأثیر می‌گذارد.

 

تابع selectMovie دقیقاً شی داده خاص را انتخاب می کند و آن را برای ویرایش به نقشه ارائه می کند. روش فیلتر در اینجا با کلیک روی دکمه Update که به داده های رندر شده گره خورده است، آن شی خاص را بر اساس شناسه آن انتخاب می کند.

 

در نهایت، ما روش Patch را پیاده سازی می کنیم که به طور خاص داده های خاص شناسه انتخاب شده توسط تابع selectMovie را که در بالا توضیح دادیم ویرایش و به روز می کند. بنابراین، پس از کلیک بر روی دکمه به روز رسانی پس از ویرایش داده ها در فرم، داده ها در API ویرایش و به روز می شوند.

با اجرای همه این موارد به درستی، مرورگر شما چیزی شبیه به این تصویر را باید نمایش می دهد:

هنگامی که سرور محلی شما به طور خودکار بارگیری می شود، باید مشاهده کنید که داده های API که اضافه کرده ایم در مرورگر نمایش داده شده است.

البته، قسمت سمت چپ این تصویر، داده های API است که قبلاً برای اهداف آزمایشی اضافه و ویرایش کرده ام. می توانید از طریق فرم سمت راست موارد بیشتری را اضافه کنید و برای افزودن روی ذخیره کلیک کنید. اگر می‌خواهید داده‌های فیلم موجود را ویرایش کنید، روی دکمه نماد به‌روزرسانی کلیک کنید تا آن را انتخاب کرده و در فرم نمایش دهید، ویرایش کنید و دکمه به‌روزرسانی روی فرم را بزنید تا در بک‌اند به‌روزرسانی شود.

 

نتیجه

خوب ما در این مقاله، یاد گرفته‌ایم که چگونه با استفاده از Django Rest Framework یک API ایجاد کنیم و از روش‌های درخواست HTTP برای ایجاد داده‌های بیشتر، خواندن داده‌ها، به‌روزرسانی و در نهایت حذف آن با استفاده از برنامه React خود استفاده می‌کنیم.

شما می توانید با اجرای مجدد گام به گام این برنامه کاربردی برای درک بهتر، بیشتر در مورد انجام عملیات CRUD تمرین کنید. با خیال راحت در مورد مفاهیمی که مانند استفاده از تنظیمات Axios از اسناد رسمی اینجا واضح به نظر نمی رسند، بیشتر کاوش کنید.

محمدرضا حسنی

224 مطلب منتشر شده

دانش آموخته رشته فناوری اطلاعات / موسس پایتونی ها

درباره این مطلب نظر دهید !

محصولات فروش پایتونی ها

%60
تخفیف

آموزش فیگما (Figma)

30,000 تومان
2