Sự cố tiêm phụ thuộc với FastAPI trên Python
Ngày tốt! Vui lòng cho tôi biết làm cách nào bạn có thể giải quyết vấn đề sau trong Python + FastAPI.
Có một dự án thử nghiệm:
app / main.py - main file
app / routes / users.py -set of api methods
app / repos / factory.py - repository factory
app / repos / user_repository.py - repositories
app / handlers / factory.py - handler factory
app / handlers / users.py - handlers
app / domain / user.py - data class
Cấu trúc tuyến đường chính và tuyến đường giống như trong ví dụ https://fastapi.tiangolo.com/tutorial/bigger-applications/
Trong tệp route / users.py :
from fastapi import APIRouter, Depends
from ..handlers import factory
router = APIRouter()
@router.get("/users/", tags=["users"])
def read_users(handler=Depends(factory.get_handler)):
return handler.get_all()
Trong trình xử lý / factory.py :
from fastapi import Depends
from .users import UserHandler1
def get_handler(handler=Depends(UserHandler1)):
return handler
Trong trình xử lý / users.py :
from fastapi import Depends
from ..repos import factory
class UserHandler1:
def __init__(self):
pass
def get_all(self, repo=Depends(factory.get_repo)):
return repo.get_all()
repos / factory.py :
from fastapi import Depends
from ..repos.user_repository import UserRepository
def get_repo(repo=Depends(UserRepository)):
return repo
repos / user_repository.py :
from ..domain.user import User
class UserRepository:
def __init__(self):
pass
def get_all(self):
return [User(1, 'A'), User(2, 'B'), User(3, 'C')]
domain / user.py :
class User:
id: int
name: str
def __init__(self, id, name):
self.id = id
self.name = name
Sau đó, tôi chạy máy chủ hypercorn: app.main:app --reloadHãy thử gọi phương thức api: http://127.0.0.1:8000/users/Và gặp lỗi AttributeError:'Depends' object has no attribute 'get_all'
Nếu bạn loại bỏ lớp trình xử lý và làm điều này, thì mọi thứ sẽ hoạt động.
route / users.py:
from fastapi import APIRouter, Depends
from ..repos import factory
router = APIRouter()
@router.get("/users/", tags=["users"])
def read_users(repo=Depends(factory.get_repo)):
return repo.get_all()
It also works if you completely remove all Depends and create
UserRepository and UserHandler1 directly in factories.
Câu hỏi 1: Làm thế nào để sử dụng "Phụ thuộc" trong trường hợp này và tại sao nó không hoạt động?
Nhìn chung, nhà máy có vẻ không phải là một giải pháp tốt cho vấn đề này. Tôi đã thấy một ví dụ về việc triển khai DI bằng cách sử dụng đa kế thừa nhưng đối với tôi, nó giống như phương pháp gốc. Tôi cũng đã cố gắng sử dụng thư viện Pinject, nhưng nó yêu cầu xây dựng ban đầu của một đồ thị, cần được lưu ở đâu đó để truy cập nó trong các trình xử lý api.
Câu hỏi 2 (quan trọng hơn): Làm thế nào để áp dụng Dependency Injection trong trường hợp này?
Trả lời
Như đã lưu ý trong các nhận xét, phụ thuộc có thể là bất kỳ thứ gì có thể gọi được và do đó cũng là một lớp. Cảnh báo duy nhất trong trường hợp sau là lớp sẽ chỉ được khởi tạo (tức là chỉ hàm init (..) mới được gọi).
Vì vậy, để có một lớp là phụ thuộc, như trong ví dụ về https://fastapi.tiangolo.com/tutorial/dependencies/classes-as-dependencies/#shortcutbạn chỉ cần gọi các hàm đích trong init và đặt các giá trị làm thuộc tính của lớp.
from ..domain.user import User
class UserRepository:
def __init__(self):
self.get_all()
def get_all(self):
self.users = [User(1, 'A'), User(2, 'B'), User(3, 'C')]
from fastapi import Depends
from ..repos.user_repository import UserRepository
def get_repo(repo=Depends(UserRepository)):
print(repo.users) # This will print the list of users
return repo
CÂU HỎI 2
NB
Đây là một câu hỏi mô hình hóa. Ở đây tôi đề xuất những gì tôi tin là phù hợp theo quan điểm của tôi . Nó không nhất thiết phải là cách tiếp cận tốt nhất hoặc đơn giản nhất.
Trả lời câu hỏi thứ hai của bạn, tôi sẽ không đưa ra lời khuyên cho những phụ thuộc phức tạp như vậy. Nếu các phụ thuộc ở cấp bộ định tuyến, bạn có thể chỉ cần thêm chúng vào bộ định tuyến, sử dụng tham số depends=[...]và cung cấp danh sách các lớp / chức năng phụ thuộc.
Ngoài ra, bạn có thể khai báo tất cả các phụ thuộc dưới dạng tham số hàm của điểm cuối, như bạn đã làm đối với nhà máy. Phương pháp này có thể dẫn đến nhiều đoạn mã bị sao chép và dán, vì vậy tôi khuyên bạn nên thực hiện phương pháp trên.
Nếu bạn cần xử lý các tham số dữ liệu, thì bạn thêm chúng vào yêu cầu và truy cập chúng từ bên trong điểm cuối. Xem FastAPI lấy ID người dùng từ khóa API để biết một ví dụ nhỏ nhất.