Peewee: Der eleganteste ORM in der Python-Geschichte
Ethan Miller
Product Engineer · Leapcell

Peewee Query Tutorial: Effiziente Datenmanipulation mit einem schlanken ORM
In der Python-Datenbankentwicklung sind Object Relational Mapping (ORM)-Bibliotheken unverzichtbare Werkzeuge für Entwickler. Peewee, ein schlanker ORM, zeichnet sich durch seine Einfachheit und Benutzerfreundlichkeit aus. Dieses Tutorial befasst sich eingehend mit den Abfragefunktionen von Peewee, bietet Beispiele im Kontext von Benutzerdiensten, die auf Plattformen ähnlich wie Leapcell bereitgestellt werden, vergleicht es mit SQLAlchemy und analysiert die Vorteile von Peewee.
I. Grundlegende Abfrageoperationen in Peewee
(1) Datensätze erstellen
Angenommen, in einem Benutzerdienst ähnlich dem auf der Leapcell-Cloud-Plattform gibt es ein User
-Modell zum Speichern von Benutzerinformationen, einschliesslich username
, email
und plan_type
(Abonnementplan). Das Erstellen neuer Benutzerdatensätze mit Peewee ist unkompliziert:
from peewee import * # Verwenden von SQLite zur Demonstration; durch tatsächliche Datenbank in Leapcell-Bereitstellung ersetzen db = SqliteDatabase('leapcell_users.db') class User(Model): username = CharField() email = CharField(unique=True) plan_type = CharField() class Meta: database = db db.connect() db.create_tables([User]) # Erstellen eines neuen Benutzers mit Model.create() new_user = User.create(username='test_user', email='test@example.com', plan_type='basic')
Die Methode User.create()
akzeptiert Schlüsselwortargumente, die mit den Feldern des Modells übereinstimmen, fügt einen neuen Datensatz ein und gibt die erstellte Modellinstanz zurück.
(2) Batch-Einfügung
Für das Einfügen von Massendaten, z. B. das Migrieren von Benutzern zu Leapcell:
user_data = [ {'username': 'user1', 'email': 'user1@example.com', 'plan_type': 'pro'}, {'username': 'user2', 'email': 'user2@example.com', 'plan_type': 'basic'}, {'username': 'user3', 'email': 'user3@example.com', 'plan_type': 'enterprise'} ] # Batch-Einfügung mit insert_many() with db.atomic(): User.insert_many(user_data).execute()
insert_many()
akzeptiert eine Liste von Dictionaries und fügt mehrere Datensätze in einer einzigen Datenbankoperation ein – weitaus effizienter als die Iteration von create()
.
(3) Datensätze aktualisieren
So aktualisieren Sie den Abonnementplan eines Benutzers auf Leapcell:
# Aktualisieren eines einzelnen Benutzers user_to_update = User.get(User.username == 'test_user') user_to_update.plan_type = 'pro' user_to_update.save() # Batch-Update: Aktualisieren aller Basisbenutzer auf Pro query = User.update(plan_type='pro').where(User.plan_type == 'basic') query.execute()
Verwenden Sie save()
für Einzelinstanzaktualisierungen oder Model.update().where()
für Massenoperationen.
(4) Datensätze löschen
So entfernen Sie Benutzer von der Plattform:
# Löschen eines einzelnen Benutzers user_to_delete = User.get(User.username == 'user1') user_to_delete.delete_instance() # Löschen mehrerer Benutzer (z. B. inaktive Konten) query = User.delete().where(User.is_deleted == True) query.execute()
Verwenden Sie delete_instance()
für einzelne Datensätze oder Model.delete().where()
für bedingte Löschungen.
(5) Abfragen von Datensätzen
- Einzelne Datensatzabfragen: Rufen Sie bestimmte Benutzer mit
get()
oderget_by_id()
ab:
# Abfrage nach Primärschlüssel user = User.get_by_id(1) print(user.username, user.email, user.plan_type) # Abfrage nach anderen Feldern user = User.get(User.email == 'test@example.com')
Diese Methoden lösen "DoesNotExist" aus, wenn kein Datensatz den Kriterien entspricht.
- Abfragen mehrerer Datensätze: Verwenden Sie
select()
, um Datensätze abzurufen und zu iterieren:
# Iterieren über alle Benutzer for user in User.select(): print(user.username, user.email) # Slicing und Indizierung users_subset = User.select()[:5] for user in users_subset: print(user.username)
Peewee speichert Abfrageergebnisse standardmässig im Cache. Verwenden Sie Select.iterator()
für eine speichereffiziente Handhabung grosser Datensätze.
- Filtern von Datensätzen: Peewee unterstützt verschiedene Filtermethoden:
# Einfacher Filter pro_users = User.select().where(User.plan_type == 'pro') # Komplexe Bedingungen mit bitweisen Operatoren active_pro_users = User.select().where((User.plan_type == 'pro') & (User.is_active == True)) # IN-Abfrage specific_emails = ['user1@example.com', 'user2@example.com'] matching_users = User.select().where(User.email.in_(specific_emails))
- Sortieren von Datensätzen: Sortieren Sie die Ergebnisse mit
order_by()
:
# Aufsteigende Reihenfolge nach Benutzernamen sorted_users = User.select().order_by(User.username) # Absteigende Reihenfolge nach Registrierungszeit (unter der Annahme des Felds registered_at) recent_users = User.select().order_by(-User.registered_at) # Sortierung nach mehreren Feldern multi_sorted_users = User.select().order_by(User.plan_type, User.username)
- Paginierung und Zählen: Wesentlich für die Handhabung grosser Datensätze:
# Paginieren von Ergebnissen (Seite 2, 10 Datensätze pro Seite) paged_users = User.select().order_by(User.id).paginate(2, 10) for user in paged_users: print(user.username) # Zählen der Gesamtanzahl der Benutzer user_count = User.select().count() print(f"Total users: {user_count}") # Zählen der Benutzer nach Plantyp pro_user_count = User.select().where(User.plan_type == 'pro').count()
- Aggregation und skalare Abfragen: Analysieren Sie Daten mit Aggregatfunktionen:
from peewee import fn # Zählen der Benutzer pro Plantyp query = (User .select(User.plan_type, fn.Count(User.id).alias('count')) .group_by(User.plan_type)) for result in query: print(result.plan_type, result.count) # Abrufen eines skalaren Werts (z. B. maximale Benutzer-ID) max_id = User.select(fn.Max(User.id)).scalar()
- Fensterfunktionen: Führen Sie Berechnungen über Ergebnismengen hinweg durch:
from peewee import Window, fn # Berechnen des Registrierungsrangs innerhalb jedes Plantyps query = User.select( User.username, User.plan_type, fn.RANK().over( order_by=[User.registered_at], partition_by=[User.plan_type] ).alias('registration_rank') ) for user in query: print(user.username, user.plan_type, user.registration_rank)
- Wiederverwenden von Fensterdefinitionen: Vereinfachen Sie komplexe Abfragen mit Fensterobjekten:
# Wiederverwendbare Fensterdefinition win = Window(order_by=[User.registered_at], partition_by=[User.plan_type]) query = User.select( User.username, User.plan_type, fn.RANK().over(win).alias('rank1'), fn.DENSE_RANK().over(win).alias('rank2') ).window(win) # Mehrere Fensterdefinitionen win1 = Window(order_by=[User.registered_at]).alias('win1') win2 = Window(partition_by=[User.plan_type]).alias('win2') query = User.select( User.username, User.plan_type, fn.SUM(User.login_count).over(win1).alias('total_logins'), fn.AVG(User.login_count).over(win2).alias('avg_logins') ).window(win1, win2)
- Rahmentypen: RANGE vs ROWS vs GROUPS: Steuern Sie Fensterfunktionsberechnungen:
# Beispiel mit dem Rahmentyp ROWS class Sample(Model): counter = IntegerField() value = FloatField() class Meta: database = db db.create_tables([Sample]) # Einfügen von Testdaten data = [(1, 10), (1, 20), (2, 1), (2, 3), (3, 100)] Sample.insert_many(data, fields=[Sample.counter, Sample.value]).execute() # Berechnen der laufenden Summe mit dem Rahmen ROWS query = Sample.select( Sample.counter, Sample.value, fn.SUM(Sample.value).over( order_by=[Sample.id], frame_type=Window.ROWS ).alias('rsum') ) for sample in query: print(sample.counter, sample.value, sample.rsum)
- Abrufen von Daten als Tupel oder Dictionaries: Überspringen Sie die Modellinstanziierung für mehr Effizienz:
# Rückgabe der Ergebnisse als Dictionaries query = User.select(User.username, User.plan_type).dicts() for user_dict in query: print(user_dict['username'], user_dict['plan_type']) # Rückgabe der Ergebnisse als Tupel query = User.select(User.username, User.plan_type).tuples() for user_tuple in query: print(user_tuple[0], user_tuple[1])
- RETURNING-Klausel: Rufen Sie geänderte Daten ab (PostgreSQL):
from peewee import PostgresqlDatabase # PostgreSQL Verbindung db = PostgresqlDatabase('leapcell_db', user='user', password='password', host='localhost', port=5432) class User(Model): username = CharField() email = CharField(unique=True) plan_type = CharField() class Meta: database = db # Aktualisieren mit RETURNING query = (User .update(plan_type='enterprise') .where(User.username == 'test_user') .returning(User)) for updated_user in query.execute(): print(updated_user.username, updated_user.plan_type)
- Common Table Expressions (CTEs): Vereinfachen Sie komplexe Abfragen:
from peewee import CTE class UserActivity(Model): user = ForeignKeyField(User) action_time = DateTimeField() class Meta: database = db db.create_tables([UserActivity]) # CTE zur Berechnung des durchschnittlichen Aktivitätsintervalls cte = (UserActivity .select(UserActivity.user, fn.AVG(fn.JULIANDAY(UserActivity.action_time) - fn.JULIANDAY(fn.LAG(UserActivity.action_time).over(order_by=[UserActivity.user, UserActivity.action_time]))).alias('avg_interval')) .group_by(UserActivity.user) .cte('user_activity_intervals')) # Abfragen von Benutzern mit einem durchschnittlichen Intervall < 1 Tag query = (User .select(User.username) .join(cte, on=(User.id == cte.c.user)) .where(cte.c.avg_interval < 1) .with_cte(cte)) for user in query: print(user.username)
II. Peewee vs SQLAlchemy
(1) Lernkurve
Die API von Peewee ist intuitiv und anfängerfreundlich, mit einer Abfragesyntax, die der natürlichen Sprache ähnelt. SQLAlchemy ist zwar funktionsreich, hat aber aufgrund seiner Komplexität eine steilere Lernkurve, insbesondere bei erweitertem Mapping und Transaktionsmanagement.
(2) Leistung
Bei einfachen Abfragen schneiden beide ORMs ähnlich ab. Das schlanke Design und die prägnante SQL-Generierung von Peewee verschaffen ihm jedoch bei komplexen Operationen mit grossen Datensätzen einen Vorteil. Der Overhead von SQLAlchemy durch seinen umfangreichen Funktionsumfang kann die Leistung in bestimmten Szenarien beeinträchtigen.
(3) Anwendungsfälle
Peewee eignet sich hervorragend für Rapid Prototyping und schlanke Anwendungen, bei denen Einfachheit und Geschwindigkeit Priorität haben. Es ist ideal für Module auf Plattformen wie Leapcell. SQLAlchemy eignet sich besser für gross angelegte Unternehmensanwendungen mit komplexen Beziehungen und erweiterten Transaktionsanforderungen.
III. Fazit
Peewee bietet einen optimierten Ansatz für Datenbankoperationen und ist damit die erste Wahl für Entwickler, die Wert auf Effizienz und Benutzerfreundlichkeit legen. Anhand von Beispielen, die von Leapcells Benutzerdienst-Ökosystem inspiriert sind, demonstriert dieses Tutorial die Möglichkeiten von Peewee bei CRUD-Operationen, Aggregationen und erweiterten Abfragen. Im Vergleich zu SQLAlchemy zeichnet sich Peewee durch eine geringere Lernkurve, Leistungsvorteile und Eignung für die schnelle Entwicklung aus. Wählen Sie Peewee für Projekte, bei denen Agilität und ein schlankes Design im Vordergrund stehen. # Peewee Query Tutorial: The Efficient Python ORM
Introduction
In Python database development, Object Relational Mapping (ORM) tools simplify interactions with databases. Peewee, a lightweight yet powerful ORM, offers developers an elegant and efficient way to query databases. Whether deployed locally or on cloud platforms like Leapcell, Peewee delivers exceptional performance. This article explores Peewee's query capabilities, contrasts it with SQLAlchemy, and illustrates its advantages through real-world examples from Leapcell's ecosystem.
Peewee Basic Query Operations
Creating Records
On the Leapcell platform, managing user data requires defining models:
from peewee import * # Connect to the database (configuration auto-detectable on Leapcell) db = SqliteDatabase('leapcell_users.db') class BaseModel(Model): class Meta: database = db class User(BaseModel): username = CharField(unique=True) email = CharField() created_at = DateTimeField(default=datetime.datetime.now) is_active = BooleanField(default=True) class Service(BaseModel): name = CharField() user = ForeignKeyField(User, backref='services') status = CharField(default='pending') deployed_at = DateTimeField(null=True)
To create a new user on Leapcell:
# Create a user on Leapcell try: user = User.create(username='alice', email='alice@example.com') print(f"User {user.username} created successfully") except IntegrityError: print("Username already exists")
Batch Insertion
Importing multiple users into Leapcell:
# Simulate bulk user data from Leapcell API users_data = [ {'username': 'bob', 'email': 'bob@example.com'}, {'username': 'charlie', 'email': 'charlie@example.com'}, {'username': 'david', 'email': 'david@example.com'} ] # Batch insert into Leapcell's database with db.atomic(): User.insert_many(users_data).execute()
Updating Records
Updating a service status on Leapcell:
# Update service status on Leapcell service = Service.get(Service.name == 'web-app' and Service.user == user) service.status = 'running' service.deployed_at = datetime.datetime.now() service.save()
Deleting Records
Removing a service on Leapcell:
# Delete a service on Leapcell service = Service.get(Service.name == 'old-service' and Service.user == user) service.delete_instance()
Querying Records
Retrieving users and their services on Leapcell:
# Query active users and their running services on Leapcell query = (User .select(User, Service) .join(Service, JOIN.LEFT_OUTER) .where(User.is_active == True) .order_by(User.username)) for user in query: print(f"User: {user.username}") if user.services: for service in user.services: print(f" Service: {service.name} ({service.status})") else: print(" No services")
Peewee Advanced Query Techniques
Aggregation Queries
Counting services per user on Leapcell:
# Count services per user on Leapcell query = (User .select(User, fn.Count(Service.id).alias('service_count')) .join(Service, JOIN.LEFT_OUTER) .group_by(User) .order_by(SQL('service_count').desc())) for user in query: print(f"User: {user.username}, Services: {user.service_count}")
Window Functions
Analyzing deployment order on Leapcell:
# Analyze deployment order with window functions query = (Service .select( Service.name, Service.deployed_at, fn.RANK().over(order_by=[Service.deployed_at.desc()]).alias('deploy_rank') ) .where(Service.deployed_at.is_null(False))) for service in query: print(f"Service: {service.name}, Deployment Rank: {service.deploy_rank}")
Common Table Expressions
Complex queries using CTEs on Leapcell:
# Query active users and their services in the last 30 days active_users_cte = (User .select(User.id) .where(User.last_login > datetime.datetime.now() - datetime.timedelta(days=30)) .cte('active_users')) query = (Service .select(Service, User.username) .join(User) .with_cte(active_users_cte) .where(User.id == active_users_cte.c.id)) for service in query: print(f"Active User {service.user.username}'s Service: {service.name}")
Why Peewee Shines as an ORM
Lightweight Design
Peewee's minimalistic architecture reduces overhead, making it ideal for cloud platforms like Leapcell. Its simplicity speeds up development and deployment compared to heavier ORMs like SQLAlchemy.
Performance Edge
Peewee generates efficient SQL, excelling in high-volume operations. For instance, its batch insertion outperforms SQLAlchemy's default approach, critical for scaling applications on Leapcell.
Flexible Database Support
Peewee seamlessly supports SQLite, PostgreSQL, MySQL, and more. This flexibility ensures compatibility with Leapcell's diverse database offerings while maintaining a consistent API.
Intuitive API
Peewee's Pythonic syntax aligns with developer expectations, reducing boilerplate code. This simplicity accelerates development cycles on Leapcell, letting teams focus on features rather than ORM intricacies.
Conclusion
Peewee is a versatile ORM that combines simplicity, performance, and flexibility—qualities essential for cloud-based services like Leapcell. Through practical examples, this tutorial has demonstrated Peewee's capabilities in both basic and advanced scenarios. When compared to SQLAlchemy, Peewee emerges as the preferred choice for projects prioritizing speed, scalability, and developer productivity.
Leapcell: The Best of Serverless Web Hosting
Finally, I recommend the perfect platform for deploying Python services: Leapcell
🚀 Build with Your Favorite Language
Develop effortlessly in JavaScript, Python, Go, or Rust.
🌍 Deploy Unlimited Projects for Free
Only pay for what you use—no requests, no charges.
⚡ Pay-as-You-Go, No Hidden Costs
No idle fees, just seamless scalability.
🔹 Follow us on Twitter: @LeapcellHQ