Ek Modeller¶
🌐 Yapay Zekâ ve İnsanlar Tarafından Çeviri
Bu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu. 🤝
Orijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖
Yapay zekâ LLM'ini daha iyi yönlendirmemize yardımcı olarak bu çeviriyi iyileştirebilirsiniz.
Önceki örnekten devam edersek, birbiriyle ilişkili birden fazla modelin olması oldukça yaygındır.
Bu durum özellikle kullanıcı modellerinde sık görülür, çünkü:
- input modeli bir
passwordiçerebilmelidir. - output modeli
passwordiçermemelidir. - database modeli büyük ihtimalle hash'lenmiş bir
passwordtutmalıdır.
Tehlike
Kullanıcının düz metin (plaintext)password'ünü asla saklamayın. Her zaman sonradan doğrulayabileceğiniz "güvenli bir hash" saklayın.
Eğer bilmiyorsanız, "password hash" nedir konusunugüvenlik bölümlerinde öğreneceksiniz.
Birden Çok Model¶
password alanlarıyla birlikte modellerin genel olarak nasıl görünebileceğine ve nerelerde kullanılacaklarına dair bir fikir:
fromfastapiimportFastAPIfrompydanticimportBaseModel,EmailStrapp=FastAPI()classUserIn(BaseModel):username:strpassword:stremail:EmailStrfull_name:str|None=NoneclassUserOut(BaseModel):username:stremail:EmailStrfull_name:str|None=NoneclassUserInDB(BaseModel):username:strhashed_password:stremail:EmailStrfull_name:str|None=Nonedeffake_password_hasher(raw_password:str):return"supersecret"+raw_passworddeffake_save_user(user_in:UserIn):hashed_password=fake_password_hasher(user_in.password)user_in_db=UserInDB(**user_in.model_dump(),hashed_password=hashed_password)print("User saved! ..not really")returnuser_in_db@app.post("/user/",response_model=UserOut)asyncdefcreate_user(user_in:UserIn):user_saved=fake_save_user(user_in)returnuser_saved**user_in.model_dump() Hakkında¶
Pydantic'in.model_dump() Metodu¶
user_in,UserIn sınıfına ait bir Pydantic modelidir.
Pydantic modellerinde, model verilerini içeren birdict döndüren.model_dump() metodu bulunur.
Yani, şöyle bir Pydantic nesnesiuser_in oluşturursak:
user_in=UserIn(username="john",password="secret",email="john.doe@example.com")ve sonra şunu çağırırsak:
user_dict=user_in.model_dump()artıkuser_dict değişkeninde modelin verilerini içeren birdict vardır (Pydantic model nesnesi yerine birdict elde etmiş oluruz).
Ve eğer şunu çağırırsak:
print(user_dict)şöyle bir Pythondict elde ederiz:
{'username':'john','password':'secret','email':'john.doe@example.com','full_name':None,}Birdict'i Unpack Etmek¶
user_dict gibi birdict alıp bunu bir fonksiyona (ya da sınıfa)**user_dict ile gönderirsek, Python bunu "unpack" eder. Yaniuser_dict içindeki key ve value'ları doğrudan key-value argümanları olarak geçirir.
Dolayısıyla, yukarıdakiuser_dict ile devam edersek, şunu yazmak:
UserInDB(**user_dict)şuna eşdeğer bir sonuç üretir:
UserInDB(username="john",password="secret",email="john.doe@example.com",full_name=None,)Ya da daha net şekilde,user_dict'i doğrudan kullanarak, gelecekte içeriği ne olursa olsun:
UserInDB(username=user_dict["username"],password=user_dict["password"],email=user_dict["email"],full_name=user_dict["full_name"],)Bir Pydantic Modelinden Diğerinin İçeriğiyle Pydantic Model Oluşturmak¶
Yukarıdaki örnekteuser_dict'iuser_in.model_dump() ile elde ettiğimiz için, şu kod:
user_dict=user_in.model_dump()UserInDB(**user_dict)şuna eşdeğerdir:
UserInDB(**user_in.model_dump())...çünküuser_in.model_dump() birdict döndürür ve biz de bunuUserInDB'ye** önekiyle vererek Python'ın "unpack" etmesini sağlarız.
Böylece, bir Pydantic modelindeki verilerden başka bir Pydantic model üretmiş oluruz.
Birdict'i Unpack Etmek ve Ek Keyword'ler¶
Sonrasında, aşağıdaki gibi ek keyword argümanıhashed_password=hashed_password eklemek:
UserInDB(**user_in.model_dump(),hashed_password=hashed_password)...şuna benzer bir sonuca dönüşür:
UserInDB(username=user_dict["username"],password=user_dict["password"],email=user_dict["email"],full_name=user_dict["full_name"],hashed_password=hashed_password,)Uyarı
Ek destek fonksiyonları olanfake_password_hasher vefake_save_user sadece verinin olası bir akışını göstermek içindir; elbette gerçek bir güvenlik sağlamazlar.
Tekrarı Azaltma¶
Kod tekrarını azaltmak,FastAPI'nin temel fikirlerinden biridir.
Kod tekrarı; bug, güvenlik problemi, kodun senkron dışına çıkması (bir yeri güncelleyip diğerlerini güncellememek) gibi sorunların olasılığını artırır.
Bu modellerin hepsi verinin büyük bir kısmını paylaşıyor ve attribute adlarını ve type'larını tekrar ediyor.
Daha iyisini yapabiliriz.
Diğer modellerimiz için temel olacak birUserBase modeli tanımlayabiliriz. Sonra da bu modelden türeyen (subclass) modeller oluşturup onun attribute'larını (type deklarasyonları, doğrulama vb.) miras aldırabiliriz.
Tüm veri dönüştürme, doğrulama, dokümantasyon vb. her zamanki gibi çalışmaya devam eder.
Bu sayede modeller arasındaki farkları (plaintextpassword olan,hashed_password olan vepassword olmayan) sadece o farklılıklar olarak tanımlayabiliriz:
fromfastapiimportFastAPIfrompydanticimportBaseModel,EmailStrapp=FastAPI()classUserBase(BaseModel):username:stremail:EmailStrfull_name:str|None=NoneclassUserIn(UserBase):password:strclassUserOut(UserBase):passclassUserInDB(UserBase):hashed_password:strdeffake_password_hasher(raw_password:str):return"supersecret"+raw_passworddeffake_save_user(user_in:UserIn):hashed_password=fake_password_hasher(user_in.password)user_in_db=UserInDB(**user_in.model_dump(),hashed_password=hashed_password)print("User saved! ..not really")returnuser_in_db@app.post("/user/",response_model=UserOut)asyncdefcreate_user(user_in:UserIn):user_saved=fake_save_user(user_in)returnuser_savedUnion veyaanyOf¶
Bir response'u iki ya da daha fazla type'ınUnion'ı olarak tanımlayabilirsiniz; bu, response'un bunlardan herhangi biri olabileceği anlamına gelir.
OpenAPI'de buanyOf ile tanımlanır.
Bunu yapmak için standart Python type hint'i olantyping.Union'ı kullanın:
Not
BirUnion tanımlarken en spesifik type'ı önce, daha az spesifik olanı sonra ekleyin. Aşağıdaki örnekte daha spesifik olanPlaneItem,Union[PlaneItem, CarItem] içindeCarItem'dan önce gelir.
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classBaseItem(BaseModel):description:strtype:strclassCarItem(BaseItem):type:str="car"classPlaneItem(BaseItem):type:str="plane"size:intitems={"item1":{"description":"All my friends drive a low rider","type":"car"},"item2":{"description":"Music is my aeroplane, it's my aeroplane","type":"plane","size":5,},}@app.get("/items/{item_id}",response_model=PlaneItem|CarItem)asyncdefread_item(item_id:str):returnitems[item_id]Python 3.10'daUnion¶
Bu örnekteUnion[PlaneItem, CarItem] değeriniresponse_model argümanına veriyoruz.
Bunu birtype annotation içine koymak yerine birargümana değer olarak geçtiğimiz için, Python 3.10'da bileUnion kullanmamız gerekiyor.
Eğer bu bir type annotation içinde olsaydı, dikey çizgiyi kullanabilirdik:
some_variable:PlaneItem|CarItemAncak bunuresponse_model=PlaneItem | CarItem atamasına koyarsak hata alırız; çünkü Python bunu bir type annotation olarak yorumlamak yerinePlaneItem ileCarItem arasındageçersiz bir işlem yapmaya çalışır.
Model Listesi¶
Aynı şekilde, nesne listesi döndüren response'ları da tanımlayabilirsiniz.
Bunun için standart Pythonlist'i kullanın:
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:stritems=[{"name":"Foo","description":"There comes my hero"},{"name":"Red","description":"It's my aeroplane"},]@app.get("/items/",response_model=list[Item])asyncdefread_items():returnitemsRastgeledict ile Response¶
Bir Pydantic modeli kullanmadan, sadece key ve value type'larını belirterek düz, rastgele birdict ile de response tanımlayabilirsiniz.
Bu, geçerli field/attribute adlarını (Pydantic modeli için gerekli olurdu) önceden bilmiyorsanız kullanışlıdır.
Bu durumdadict kullanabilirsiniz:
fromfastapiimportFastAPIapp=FastAPI()@app.get("/keyword-weights/",response_model=dict[str,float])asyncdefread_keyword_weights():return{"foo":2.3,"bar":3.4}Özet¶
Her duruma göre birden fazla Pydantic modeli kullanın ve gerekirse özgürce inheritance uygulayın.
Bir entity'nin farklı "state"lere sahip olması gerekiyorsa, o entity için tek bir veri modeli kullanmak zorunda değilsiniz. Örneğinpassword içeren,password_hash içeren vepassword içermeyen state'lere sahip kullanıcı "entity"si gibi.







