1.3 מסד נתונים רלציוני פתרון
פתרון תרגול – הרחבת פרויקט TRIP עם קשרים רלציוניים (מלונות וטיסות)¶
1. דוגמת מחלקות SQLAlchemy לקשרי many-to-many – מלונות, טיולים וטיסות¶
from sqlalchemy import Column, Integer, String, ForeignKey, Table
from sqlalchemy.orm import relationship, declarative_base
Base = declarative_base()
# טבלה מקשרת בין טיולים למלונות
trip_hotels = Table(
'trip_hotels', Base.metadata,
Column('trip_id', ForeignKey('trips.id'), primary_key=True),
Column('hotel_id', ForeignKey('hotels.id'), primary_key=True)
)
# טבלה מקשרת בין טיולים לטיסות
trip_flights = Table(
'trip_flights', Base.metadata,
Column('trip_id', ForeignKey('trips.id'), primary_key=True),
Column('flight_id', ForeignKey('flights.id'), primary_key=True)
)
class Hotel(Base):
__tablename__ = 'hotels'
id = Column(Integer, primary_key=True)
name = Column(String)
stars = Column(Integer)
trips = relationship('Trip', secondary=trip_hotels, back_populates='hotels')
class Flight(Base):
__tablename__ = 'flights'
id = Column(Integer, primary_key=True)
airline = Column(String)
from_city = Column(String)
to_city = Column(String)
trips = relationship('Trip', secondary=trip_flights, back_populates='flights')
class Trip(Base):
__tablename__ = 'trips'
id = Column(Integer, primary_key=True)
name = Column(String)
people = Column(Integer)
hotels = relationship('Hotel', secondary=trip_hotels, back_populates='trips')
flights = relationship('Flight', secondary=trip_flights, back_populates='trips')
2. דוגמת שימוש – הוספה ושליפה¶
# יצירת טיול חדש עם מלונות וטיסות
h1 = Hotel(name="Hilton", stars=5)
h2 = Hotel(name="Dan", stars=4)
f1 = Flight(airline="EL AL", from_city="TLV", to_city="LHR")
f2 = Flight(airline="EasyJet", from_city="TLV", to_city="AMST")
t = Trip(name="טיול ללונדון", people=3, hotels=[h1, h2], flights=[f1, f2])
session.add_all([h1,h2,f1,f2,t])
session.commit()
# שליפת כל המלונות של טיול מסוים
trip = session.query(Trip).filter_by(name="טיול ללונדון").first()
print([hotel.name for hotel in trip.hotels])
# שליפת כל הטיולים של מלון מסוים
hotel = session.query(Hotel).filter_by(name="Hilton").first()
print([trip.name for trip in hotel.trips])
# שליפת כל הטיסות של טיול מסוים
print([flight.airline for flight in trip.flights])
# שליפת כל הטיולים של טיסה מסוימת
flight = session.query(Flight).filter_by(airline="EL AL").first()
print([trip.name for trip in flight.trips])
3. דוגמת קונטרולר בפייתון¶
# controllers/trip_relations_controller.py
from sqlalchemy.orm import Session
def get_hotels_for_trip(trip_id: int, db: Session):
trip = db.query(Trip).get(trip_id)
return [hotel.name for hotel in trip.hotels]
def get_trips_for_hotel(hotel_id: int, db: Session):
hotel = db.query(Hotel).get(hotel_id)
return [trip.name for trip in hotel.trips]
def get_flights_for_trip(trip_id: int, db: Session):
trip = db.query(Trip).get(trip_id)
return [flight.airline for flight in trip.flights]
def get_trips_for_flight(flight_id: int, db: Session):
flight = db.query(Flight).get(flight_id)
return [trip.name for trip in flight.trips]
4. דוגמת route-ים שמשתמשים ב-controller ב-FastAPI¶
# routes/trip_relations.py
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from database import get_db
from controllers.trip_relations_controller import (
get_hotels_for_trip,
get_trips_for_hotel,
get_flights_for_trip,
get_trips_for_flight
)
router = APIRouter()
@router.get("/trips/{trip_id}/hotels")
def hotels_for_trip(trip_id: int, db: Session = Depends(get_db)):
return get_hotels_for_trip(trip_id, db)
@router.get("/hotels/{hotel_id}/trips")
def trips_for_hotel(hotel_id: int, db: Session = Depends(get_db)):
return get_trips_for_hotel(hotel_id, db)
@router.get("/trips/{trip_id}/flights")
def flights_for_trip(trip_id: int, db: Session = Depends(get_db)):
return get_flights_for_trip(trip_id, db)
@router.get("/flights/{flight_id}/trips")
def trips_for_flight(flight_id: int, db: Session = Depends(get_db)):
return get_trips_for_flight(flight_id, db)
כל ה-endpoints יתועדו אוטומטית ב-/docs של FastAPI.
- כך ניתן לנהל מערכת Trips שבה כל טיול יכול לכלול כמה מלונות וכמה טיסות, וכל מלון/טיסה יכולים להשתייך למספר טיולים שונים.