הקדמה
במדריך זה נבנה אפליקציה מלאה המשתמשת ב-Django לשרת (Backend) וב-React עם TypeScript לצד הלקוח (Frontend). האפליקציה תדמה מערכת השאלת ספרים מהספרייה, ותכלול ניהול מנויים, ספרים והשאלות. נשתמש ב-Django Rest Framework (DRF) כדי לבנות API שיאפשר תקשורת בין ה-Backend ל-Frontend.
שלב 1: התקנת הכלים הנדרשים
- Python: הורד והתקן את Python מהאתר הרשמי: Python Downloads.
- Node.js: הורד והתקן את Node.js מהאתר הרשמי: Node.js Downloads.
- Git: הורד והתקן את Git: Git Downloads.
- Visual Studio Code: מומלץ להשתמש בעורך קוד כמו VS Code: VS Code Downloads.
שלב 2: יצירת פרויקט Django
- צור תיקייה לפרויקט: פתח את שורת הפקודה או הטרמינל והקלד:
mkdir library_project
cd library_project
- צור סביבה וירטואלית:
python -m venv venv
- הפעל את הסביבה הוירטואלית:
- ב-Windows:
venv\Scripts\activate
- ב-macOS/Linux:
source venv/bin/activate
- התקן את Django ו-DRF:
pip install django djangorestframework
- צור פרויקט Django:
django-admin startproject backend .
- צור אפליקציה בשם "library":
python manage.py startapp library
- הוסף את האפליקציה וה-DRF לקובץ ההגדרות: ערוך את הקובץ
backend/settings.py
והוסף את 'rest_framework' ו-'library' ל-INSTALLED_APPS
:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'library',
]
שלב 3: הגדרת מודלים (Models)
- פתח את הקובץ
library/models.py
והוסף את הקוד הבא:
from django.db import models
class Subscriber(models.Model):
name = models.CharField(max_length=100)
children_count = models.PositiveIntegerField()
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
copies_available = models.PositiveIntegerField(default=1)
def __str__(self):
return self.title
class Loan(models.Model):
subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
loan_date = models.DateField(auto_now_add=True)
def __str__(self):
return f"{self.subscriber.name} borrowed {self.book.title}"
הסבר:
- Subscriber: מודל המייצג מנוי, עם שם ומספר ילדים.
- Book: מודל המייצג ספר, עם כותרת, מחבר ומספר עותקים זמינים.
- Loan: מודל המייצג השאלה של ספר על ידי מנוי, כולל תאריך ההשאלה.
- ביצוע מיגרציות:
- צור קבצי מיגרציה:
python manage.py makemigrations
- החל את המיגרציות:
python manage.py migrate
שלב 4: יצירת Serializers
- צור קובץ בשם
library/serializers.py
והוסף את הקוד:
from rest_framework import serializers
from .models import Subscriber, Book, Loan
class SubscriberSerializer(serializers.ModelSerializer):
class Meta:
model = Subscriber
fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
class LoanSerializer(serializers.ModelSerializer):
class Meta:
model = Loan
fields = '__all__'
def validate(self, data):
subscriber = data['subscriber']
loans_count = Loan.objects.filter(subscriber=subscriber).count()
if loans_count >= subscriber.children_count:
raise serializers.ValidationError('המנוי הגיע למספר ההשאלות המקסימלי.')
return data
הסבר:
- Serializers משמשים להמרת מודלים לפורמט JSON ולהיפך.
- ב-
LoanSerializer
הוספנו ולידציה כדי לוודא שמנוי לא יכול להשאיל יותר ספרים מהמותר לו.
שלב 5: יצירת ViewSets
- ערוך את הקובץ
library/views.py
והוסף את הקוד:
from rest_framework import viewsets
from .models import Subscriber, Book, Loan
from .serializers import SubscriberSerializer, BookSerializer, LoanSerializer
class SubscriberViewSet(viewsets.ModelViewSet):
queryset = Subscriber.objects.all()
serializer_class = SubscriberSerializer
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
class LoanViewSet(viewsets.ModelViewSet):
queryset = Loan.objects.all()
serializer_class = LoanSerializer
הסבר:
- ViewSets מספקים פעולות CRUD למודלים שלנו.
שלב 6: הגדרת הנתיבים (URLs)
- צור קובץ בשם
library/urls.py
והוסף:
from django.urls import path, include
from rest_framework import routers
from .views import SubscriberViewSet, BookViewSet, LoanViewSet
router = routers.DefaultRouter()
router.register(r'subscribers', SubscriberViewSet)
router.register(r'books', BookViewSet)
router.register(r'loans', LoanViewSet)
urlpatterns = [
path('', include(router.urls)),
]
- עדכן את
backend/urls.py
כדי לכלול את הנתיבים של האפליקציה:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('library.urls')),
]
שלב 7: הגדרת CORS
- התקן את החבילה
django-cors-headers
:
pip install django-cors-headers
- הוסף ל-
INSTALLED_APPS
ב-backend/settings.py
:
INSTALLED_APPS = [
...
'corsheaders',
]
- הוסף את ה-Middleware:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...
]
- אפשר גישה מכל המקורות:
CORS_ALLOW_ALL_ORIGINS = True
שלב 8: הרצת שרת Django
- הפעל את השרת:
python manage.py runserver
- בדיקה: גש לדפדפן לכתובת http://localhost:8000/api/ ותראה את ה-API.
שלב 9: יצירת פרויקט React עם TypeScript
- בטרמינל חדש, בתיקיית הפרויקט, הרץ:
npx create-react-app frontend --template typescript
- התקן את axios:
cd frontend
npm install axios
שלב 10: בניית ה-Frontend
- יצירת סוגים (Types):
- צור תיקייה
src/types
. - צור קובץ
types.ts
עם התוכן:export interface Subscriber { id?: number; name: string; children_count: number; } export interface Book { id?: number; title: string; author: string; copies_available: number; } export interface Loan { id?: number; subscriber: number; book: number; loan_date?: string; }
- יצירת שירות API:
- צור תיקייה
src/services
. - צור קובץ
api.ts
עם התוכן:import axios from 'axios'; const api = axios.create({ baseURL: 'http://localhost:8000/api/', }); export default api;
- יצירת רכיבים (Components):
- צור תיקייה
src/components
. - צור רכיב
BookList.tsx
:import React, { useEffect, useState } from 'react'; import api from '../services/api'; import { Book } from '../types/types'; const BookList: React.FC = () => { const [books, setBooks] = useState<Book[]>([]); useEffect(() => { api.get<Book[]>('books/').then(response => { setBooks(response.data); }); }, []); return ( <div> <h2>רשימת ספרים</h2> <ul> {books.map(book => ( <li key={book.id}> {book.title} מאת {book.author} - עותקים זמינים: {book.copies_available} </li> ))} </ul> </div> ); }; export default BookList;
- עדכון
App.tsx
:
import React from 'react';
import BookList from './components/BookList';
function App() {
return (
<div className="App">
<h1>מערכת השאלת ספרים</h1>
<BookList />
</div>
);
}
export default App;
שלב 11: הרצת אפליקציית React
- הפעל את האפליקציה:
npm start
- בדיקה: גש לדפדפן לכתובת http://localhost:3000 ותראה את רשימת הספרים.
שלב 12: הוספת רכיבים נוספים
- רשימת מנויים (
SubscriberList.tsx
):
import React, { useEffect, useState } from 'react';
import api from '../services/api';
import { Subscriber } from '../types/types';
const SubscriberList: React.FC = () => {
const [subscribers, setSubscribers] = useState<Subscriber[]>([]);
useEffect(() => {
api.get<Subscriber[]>('subscribers/').then(response => {
setSubscribers(response.data);
});
}, []);
return (
<div>
<h2>רשימת מנויים</h2>
<ul>
{subscribers.map(subscriber => (
<li key={subscriber.id}>
{subscriber.name} - מספר ילדים: {subscriber.children_count}
</li>
))}
</ul>
</div>
);
};
export default SubscriberList;
- הוספת מנוי חדש (
AddSubscriber.tsx
):
import React, { useState } from 'react';
import api from '../services/api';
import { Subscriber } from '../types/types';
const AddSubscriber: React.FC = () => {
const [name, setName] = useState('');
const [childrenCount, setChildrenCount] = useState(0);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const newSubscriber: Subscriber = { name, children_count: childrenCount };
api.post('subscribers/', newSubscriber).then(response => {
alert('מנוי נוסף בהצלחה!');
});
};
return (
<form onSubmit={handleSubmit}>
<h2>הוסף מנוי</h2>
<label>
שם:
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</label>
<br />
<label>
מספר ילדים:
<input type="number" value={childrenCount} onChange={e => setChildrenCount(parseInt(e.target.value))} />
</label>
<br />
<button type="submit">הוסף</button>
</form>
);
};
export default AddSubscriber;
- עדכון
App.tsx
:
import React from 'react';
import BookList from './components/BookList';
import SubscriberList from './components/SubscriberList';
import AddSubscriber from './components/AddSubscriber';
function App() {
return (
<div className="App">
<h1>מערכת השאלת ספרים</h1>
<AddSubscriber />
<SubscriberList />
<BookList />
</div>
);
}
export default App;
שלב 13: הוספת השאלות
- רכיב השאלת ספר (
LoanBook.tsx
):
import React, { useState, useEffect } from 'react';
import api from '../services/api';
import { Subscriber, Book, Loan } from '../types/types';
const LoanBook: React.FC = () => {
const [subscribers, setSubscribers] = useState<Subscriber[]>([]);
const [books, setBooks] = useState<Book[]>([]);
const [selectedSubscriber, setSelectedSubscriber] = useState<number | null>(null);
const [selectedBook, setSelectedBook] = useState<number | null>(null);
useEffect(() => {
api.get<Subscriber[]>('subscribers/').then(response => {
setSubscribers(response.data);
});
api.get<Book[]>('books/').then(response => {
setBooks(response.data);
});
}, []);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (selectedSubscriber && selectedBook) {
const newLoan: Loan = { subscriber: selectedSubscriber, book: selectedBook };
api.post('loans/', newLoan).then(response => {
alert('ספר הושאל בהצלחה!');
}).catch(error => {
alert('שגיאה: ' + error.response.data.detail);
});
}
};
return (
<form onSubmit={handleSubmit}>
<h2>השאלת ספר</h2>
<label>
מנוי:
<select onChange={e => setSelectedSubscriber(parseInt(e.target.value))}>
<option value="">בחר מנוי</option>
{subscribers.map(subscriber => (
<option key={subscriber.id} value={subscriber.id}>{subscriber.name}</option>
))}
</select>
</label>
<br />
<label>
ספר:
<select onChange={e => setSelectedBook(parseInt(e.target.value))}>
<option value="">בחר ספר</option>
{books.map(book => (
<option key={book.id} value={book.id}>{book.title}</option>
))}
</select>
</label>
<br />
<button type="submit">השאל</button>
</form>
);
};
export default LoanBook;
- עדכון
App.tsx
להכללת רכיב ההשאלה:
import React from 'react';
import BookList from './components/BookList';
import SubscriberList from './components/SubscriberList';
import AddSubscriber from './components/AddSubscriber';
import LoanBook from './components/LoanBook';
function App() {
return (
<div className="App">
<h1>מערכת השאלת ספרים</h1>
<AddSubscriber />
<SubscriberList />
<BookList />
<LoanBook
</div>
);
}
export default App;
שלב 14: בדיקה וסיכום
- הפעל את שרת Django ואת אפליקציית React.
- בדוק את הפונקציונליות:
- הוסף מנויים וספרים.
- נסה להשאיל ספר למנוי.
- ודא שהמערכת מונעת השאלה מעבר למספר המותר.
סיכום
יצרנו אפליקציית Django ו-React מלאה המדמה מערכת השאלת ספרים מהספרייה. הסברנו כל שלב בפירוט, והצגנו את הקוד המלא הנדרש לבנייה והפעלה של הפרויקט. השתמשנו ב-Django Rest Framework ליצירת API וב-React עם TypeScript ליצירת ממשק משתמש אינטראקטיבי.
הערות נוספות
- אין צורך בידע מוקדם בתכנות, אך ייתכן שתצטרך לחפש באינטרנט למידע נוסף על כלי הפיתוח.
- אם אתה נתקל בשגיאות, וודא שהתקנת את כל התוכנות הנדרשות ושהקוד הוזן כראוי.
- למידה נוספת: מומלץ ללמוד את היסודות של Python, Django, JavaScript, ו-React כדי להבין לעומק את האפליקציה.
כתיבת תגובה