Created
October 27, 2025 14:08
-
-
Save CoreyMSchafer/26fbfae9fb2ad293cc431530e8932855 to your computer and use it in GitHub Desktop.
Pydantic Tutorial Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import json | |
| from datetime import UTC, datetime | |
| from functools import partial | |
| from typing import Annotated, Literal | |
| from uuid import UUID, uuid4 | |
| from pydantic import ( | |
| BaseModel, | |
| ConfigDict, | |
| EmailStr, | |
| Field, | |
| HttpUrl, | |
| SecretStr, | |
| ValidationError, | |
| ValidationInfo, | |
| computed_field, | |
| field_validator, | |
| model_validator, | |
| ) | |
| class User(BaseModel): | |
| model_config = ConfigDict( | |
| populate_by_name=True, | |
| strict=True, | |
| extra="allow", | |
| frozen=True, | |
| ) | |
| uid: UUID = Field(alias="id", default_factory=uuid4) | |
| username: Annotated[str, Field(min_length=3, max_length=20)] | |
| email: EmailStr | |
| password: SecretStr | |
| website: HttpUrl | None = None | |
| age: Annotated[int, Field(ge=13, le=130)] | |
| verified_at: datetime | None = None | |
| bio: str = "" | |
| is_active: bool = True | |
| first_name: str = "" | |
| last_name: str = "" | |
| follower_count: int = 0 | |
| @field_validator("username") | |
| @classmethod | |
| def validate_username(cls, v: str) -> str: | |
| if not v.replace("_", "").isalnum(): | |
| raise ValueError("Username must be alphanumeric (underscores allowed)") | |
| return v.lower() | |
| @field_validator("website", mode="before") | |
| @classmethod | |
| def add_https(cls, v: str | None) -> str | None: | |
| if v and not v.startswith(("http://", "https://")): | |
| return f"https://{v}" | |
| return v | |
| @computed_field | |
| @property | |
| def display_name(self) -> str: | |
| if self.first_name and self.last_name: | |
| return f"{self.first_name} {self.last_name}" | |
| return self.username | |
| @computed_field | |
| @property | |
| def is_influencer(self) -> bool: | |
| return self.follower_count >= 10000 | |
| class Comment(BaseModel): | |
| content: str | |
| author_email: EmailStr | |
| likes: int = 0 | |
| class BlogPost(BaseModel): | |
| title: Annotated[str, Field(min_length=1, max_length=200)] | |
| content: Annotated[str, Field(min_length=10)] | |
| author: User | |
| view_count: int = 0 | |
| is_published: bool = False | |
| tags: list[str] = Field(default_factory=list) | |
| create_at: datetime = Field(default_factory=partial(datetime.now, tz=UTC)) | |
| status: Literal["draft", "published", "archived"] = "draft" | |
| slug: Annotated[str, Field(pattern=r"^[a-z0-9-]+$")] | |
| comments: list[Comment] = Field(default_factory=list) | |
| class UserRegistration(BaseModel): | |
| email: EmailStr | |
| password: str | |
| confirm_password: str | |
| @model_validator(mode="after") | |
| def passwords_match(self) -> "UserRegistration": | |
| if self.password != self.confirm_password: | |
| raise ValueError("Passwords do not match") | |
| return self | |
| user_data = { | |
| "id": "3bc4bf25-1b73-44da-9078-f2bb310c7374", | |
| "username": "Corey_Schafer", | |
| "email": "CoreyMSchafer@gmail.com", | |
| "age": 39, | |
| "password": "secret123", | |
| "notes": "Kind've a Karen...", | |
| } | |
| user = User.model_validate_json(json.dumps(user_data)) | |
| user.email = "CoreyMSchafer2@gmail.com" | |
| print(user.model_dump_json(indent=2)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ### New BlogPost | |
| post = BlogPost( | |
| title="Getting Started with Python", | |
| content="Here's how to begin...", | |
| author_id="12345", | |
| ) | |
| ### Invalid User | |
| try: | |
| user = User( | |
| uid=0, | |
| username="cs", | |
| email="CoreyMSchafer@gmail.com", | |
| age=12, | |
| ) | |
| except ValidationError as e: | |
| print(e) | |
| ### Valid User | |
| user = User( | |
| username="coreyms", | |
| email="CoreyMSchafer@gmail.com", | |
| age=39, | |
| password="secret123", | |
| ) | |
| print(user) | |
| ### Username Validation | |
| @field_validator('username') | |
| @classmethod | |
| def validate_username(cls, v: str) -> str: | |
| if not v.replace('_', '').isalnum(): | |
| raise ValueError('Username must be alphanumeric (underscores allowed)') | |
| return v.lower() | |
| ### URL Validation (no mode) | |
| @field_validator('website') | |
| @classmethod | |
| def add_https(cls, v: str | None) -> str | None: | |
| if v and not v.startswith(('http://', 'https://')): | |
| return f'https://{v}' | |
| return v | |
| ### Model Validator | |
| class UserRegistration(BaseModel): | |
| email: EmailStr | |
| password: str | |
| confirm_password: str | |
| @model_validator(mode='after') | |
| def passwords_match(self) -> 'UserRegistration': | |
| if self.password != self.confirm_password: | |
| raise ValueError('Passwords do not match') | |
| return self | |
| try: | |
| registration = UserRegistration( | |
| email="CoreyMSchafer@gmail.com", | |
| password="secret123", | |
| confirm_password="secret456" | |
| ) | |
| except ValidationError as e: | |
| print(e) | |
| ### Computed Fields | |
| first_name: str = "" | |
| last_name: str = "" | |
| follower_count: int = 0 | |
| @computed_field | |
| @property | |
| def display_name(self) -> str: | |
| if self.first_name and self.last_name: | |
| return f"{self.first_name} {self.last_name}" | |
| return self.username | |
| @computed_field | |
| @property | |
| def is_influencer(self) -> bool: | |
| return self.follower_count >= 10000 | |
| ### Comment Model | |
| class Comment(BaseModel): | |
| content: str | |
| author_email: EmailStr | |
| likes: int = 0 | |
| ### BlogPost Dictionary | |
| post_data = { | |
| "title": "Understanding Pydantic Models", | |
| "content": "Pydantic makes data validation easy and intuitive...", | |
| "slug": "understanding-pydantic", | |
| "author": { | |
| "username": "coreyms", | |
| "email": "CoreyMSchafer@gmail.com", | |
| "age": 39, | |
| "password": "secret123", | |
| }, | |
| "comments": [ | |
| { | |
| "content": "I think I understand nested models now!", | |
| "author_email": "student@example.com", | |
| "likes": 25, | |
| }, | |
| { | |
| "content": "Can you cover FastAPI next?", | |
| "author_email": "viewer@example.com", | |
| "likes": 15, | |
| }, | |
| ], | |
| } | |
| post = BlogPost(**post_data) | |
| print(post.model_dump_json(indent=2)) | |
| ### User Dictionary | |
| user_data = { | |
| "id": "3bc4bf25-1b73-44da-9078-f2bb310c7374", | |
| "username": "Corey_Schafer", | |
| "email": "CoreyMSchafer@gmail.com", | |
| "age": "39", | |
| "password": "secret123", | |
| } | |
| user = User.model_validate(user_data) | |
| print(user.model_dump_json(indent=2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
import 'package:flutter/material.dart';
void main() {
runApp(const OrganelOyunuApp());
}
class OrganelOyunuApp extends StatelessWidget {
const OrganelOyunuApp({super.key});
@OverRide
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Organel Eşleştirme Oyunu',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
fontFamily: 'Roboto',
),
home: const OyunEkrani(),
);
}
}
// Organel verilerini tutacağımız basit bir model sınıfı
class Organel {
final String isim;
final String gorev;
final IconData ikon;
final Color renk;
Organel({
required this.isim,
required this.gorev,
required this.ikon,
required this.renk,
});
}
class OyunEkrani extends StatefulWidget {
const OyunEkrani({super.key});
@OverRide
State createState() => _OyunEkraniState();
}
class _OyunEkraniState extends State {
// Tüm organellerin ve görevlerinin listesi
final List tumOrganeller = [
Organel(isim: 'Mitokondri', gorev: 'Hücrenin enerji (ATP) santralidir.', ikon: Icons.bolt, renk: Colors.orange),
Organel(isim: 'Ribozom', gorev: 'Protein sentezinden sorumludur.', ikon: Icons.grain, renk: Colors.redAccent),
Organel(isim: 'Kloroplast', gorev: 'Fotosentez yaparak besin ve oksijen üretir.', ikon: Icons.eco, renk: Colors.green),
Organel(isim: 'Çekirdek', gorev: 'Hücrenin yönetim ve kalıtım merkezidir.', ikon: Icons.adjust, renk: Colors.deepPurple),
Organel(isim: 'Lizozom', gorev: 'Hücre içi sindirim yapar.', ikon: Icons.delete_sweep, renk: Colors.brown),
Organel(isim: 'Golgi Aygıtı', gorev: 'Salgı maddelerini üretir ve paketler.', ikon: Icons.waves, renk: Colors.blue),
Organel(isim: 'Koful', gorev: 'Atık maddeleri ve suyu depolar.', ikon: Icons.bubble_chart, renk: Colors.teal),
];
// Doğru eşleştirilen organellerin isimlerini tuttuğumuz liste
List eslesenler = [];
// Sürüklenecek ve hedeflenecek listeleri karıştırmak için
late List suruklenecekOrganeller;
late List hedefGorevler;
@OverRide
void initState() {
super.initState();
oyunuBaslat();
}
// Oyunu sıfırlayan ve listeleri karıştıran fonksiyon
void oyunuBaslat() {
setState(() {
eslesenler.clear();
// Listeleri kopyalayıp rastgele karıştırıyoruz
suruklenecekOrganeller = List.from(tumOrganeller)..shuffle();
hedefGorevler = List.from(tumOrganeller)..shuffle();
});
}
// Oyunun bitip bitmediğini kontrol eden fonksiyon
void kontrolEtOyunBittiMi() {
if (eslesenler.length == tumOrganeller.length) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: const Text('Tebrikler! 🏆', textAlign: TextAlign.center),
content: const Text(
'Tüm hücre organellerini ve görevlerini başarıyla eşleştirdiniz. Artık tam bir biyoloji uzmanısınız!',
textAlign: TextAlign.center,
),
actionsAlignment: MainAxisAlignment.center,
actions: [
ElevatedButton.icon(
onPressed: () {
Navigator.of(context).pop();
oyunuBaslat();
},
icon: const Icon(Icons.refresh),
label: const Text('Yeniden Oyna'),
)
],
),
);
}
}
@OverRide
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('Hücre Organelleri Eşleştirme', style: TextStyle(fontWeight: FontWeight.bold)),
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Colors.white,
actions: [
Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'Skor: ${eslesenler.length} / ${tumOrganeller.length}',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
)
],
),
body: Column(
children: [
// Üst Kısım: Sürüklenebilir Organel Çipleri
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 5))
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Organelleri görevlerin üzerine sürükleyin:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87),
textAlign: TextAlign.center,
),
const SizedBox(height: 12),
Wrap(
alignment: WrapAlignment.center,
spacing: 12.0,
runSpacing: 12.0,
children: suruklenecekOrganeller.map((organel) {
// Eğer organel eşleştirildiyse boş bir kutu göster
if (eslesenler.contains(organel.isim)) {
return Chip(
label: const Text('Eşleşti ✓'),
backgroundColor: Colors.grey[300],
labelStyle: TextStyle(color: Colors.grey[600]),
);
}
}
}