postgresdb3 0.7.0__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- postgresdb3-1.0.1/PKG-INFO +302 -0
- postgresdb3-1.0.1/README.md +280 -0
- postgresdb3-1.0.1/postgresdb3/__init__.py +11 -0
- postgresdb3-1.0.1/postgresdb3/cli.py +62 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/core/async_db.py +110 -15
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/core/sync_db.py +124 -37
- postgresdb3-1.0.1/postgresdb3/migrations/__init__.py +20 -0
- postgresdb3-1.0.1/postgresdb3/migrations/engine.py +241 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/base.py +9 -2
- postgresdb3-1.0.1/postgresdb3/orm/expressions.py +80 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/fields/__init__.py +2 -2
- postgresdb3-1.0.1/postgresdb3/orm/fields/datetime.py +32 -0
- postgresdb3-1.0.1/postgresdb3/orm/fields/foreign.py +61 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/fields/numeric.py +6 -0
- postgresdb3-1.0.1/postgresdb3/orm/meta.py +117 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/models.py +120 -43
- postgresdb3-1.0.1/postgresdb3/orm/query.py +696 -0
- postgresdb3-1.0.1/postgresdb3/orm/relations.py +196 -0
- postgresdb3-1.0.1/postgresdb3.egg-info/PKG-INFO +302 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3.egg-info/SOURCES.txt +4 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/setup.py +2 -2
- postgresdb3-0.7.0/PKG-INFO +0 -251
- postgresdb3-0.7.0/README.md +0 -229
- postgresdb3-0.7.0/postgresdb3/__init__.py +0 -1
- postgresdb3-0.7.0/postgresdb3/orm/fields/datetime.py +0 -17
- postgresdb3-0.7.0/postgresdb3/orm/fields/foreign.py +0 -31
- postgresdb3-0.7.0/postgresdb3/orm/meta.py +0 -61
- postgresdb3-0.7.0/postgresdb3/orm/query.py +0 -473
- postgresdb3-0.7.0/postgresdb3/orm/relations.py +0 -44
- postgresdb3-0.7.0/postgresdb3.egg-info/PKG-INFO +0 -251
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/core/__init__.py +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/__init__.py +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/fields/base.py +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/fields/misc.py +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3/orm/fields/text.py +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3.egg-info/dependency_links.txt +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3.egg-info/requires.txt +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/postgresdb3.egg-info/top_level.txt +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/pyproject.toml +0 -0
- {postgresdb3-0.7.0 → postgresdb3-1.0.1}/setup.cfg +0 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: postgresdb3
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: High-Performance Sync and Async PostgreSQL ORM for Python
|
|
5
|
+
Author: Abdulbosit Alijonov
|
|
6
|
+
Project-URL: Source Code, https://github.com/AlijonovUz/PostgresDB
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: psycopg2>=2.9
|
|
13
|
+
Requires-Dist: asyncpg>=0.31.0
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: classifier
|
|
16
|
+
Dynamic: description
|
|
17
|
+
Dynamic: description-content-type
|
|
18
|
+
Dynamic: project-url
|
|
19
|
+
Dynamic: requires-dist
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
22
|
+
|
|
23
|
+
# PostgresDB3 - High-Performance Python ORM
|
|
24
|
+
|
|
25
|
+
**PostgresDB3** — bu PostgreSQL uchun mo'ljallangan zamonaviy, tezkor va ham **sinxron**, ham **asinxron** ishlash imkoniyatiga ega bo'lgan ORM (Object-Relational Mapping) kutubxonasi.
|
|
26
|
+
|
|
27
|
+
U Django ORM kabi qulay va oson tushuniladi, lekin o'zida asinxronlik (`asyncpg`) va ko'plab yuqori texnologik xususiyatlarni mujassamlashtirgan. Kichik botlardan tortib, o'ta katta masshtabdagi (Highload) loyihalargacha bemalol ishlata olasiz!
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 📦 O'rnatish
|
|
32
|
+
|
|
33
|
+
Kutubxonani o'rnatish uchun terminalda quyidagi buyruqni kiriting:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install postgresdb3
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 🚀 Tezkor Boshlash
|
|
42
|
+
|
|
43
|
+
PostgresDB3 bir vaqtning o'zida ikkita dunyoni qo'llab-quvvatlaydi. Xohlasangiz **Sinxron**, xohlasangiz **Asinxron** loyihalarda bir xil sintaksis bilan ishlay olasiz.
|
|
44
|
+
|
|
45
|
+
### 1. Ulanishni sozlash
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from postgresdb3 import PostgresDB, AsyncPostgresDB
|
|
49
|
+
|
|
50
|
+
# Sinxron ulanish (psycopg2 asosida)
|
|
51
|
+
db_sync = PostgresDB("my_db", "user", "password", host="localhost", port=5432, echo=True)
|
|
52
|
+
|
|
53
|
+
# Asinxron ulanish (asyncpg asosida)
|
|
54
|
+
db_async = AsyncPostgresDB("my_db", "user", "password", host="localhost", port=5432, echo=True)
|
|
55
|
+
```
|
|
56
|
+
*(Eslatma: `echo=True` yoqilsa, barcha bajarilayotgan SQL so'rovlar terminalda ko'rinib turadi, bu debug uchun juda foydali).*
|
|
57
|
+
|
|
58
|
+
### 2. Modellarni Yaratish
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from postgresdb3.orm.models import Model, AsyncModel
|
|
62
|
+
from postgresdb3 import String, Integer, Float
|
|
63
|
+
|
|
64
|
+
# Sinxron model
|
|
65
|
+
Model.db = db_sync
|
|
66
|
+
|
|
67
|
+
class User(Model):
|
|
68
|
+
name = String(length=50)
|
|
69
|
+
age = Integer(default=18)
|
|
70
|
+
score = Float(default=0.0)
|
|
71
|
+
|
|
72
|
+
# Asinxron model
|
|
73
|
+
AsyncModel.db = db_async
|
|
74
|
+
|
|
75
|
+
class AsyncUser(AsyncModel):
|
|
76
|
+
name = String(length=50)
|
|
77
|
+
age = Integer(default=18)
|
|
78
|
+
score = Float(default=0.0)
|
|
79
|
+
|
|
80
|
+
# Qo'shimcha sozlamalar (Murakkab Indekslar)
|
|
81
|
+
class Meta:
|
|
82
|
+
unique_together = (("name", "age"),) # Ism va yosh bir xil takrorlanmasligi kerak
|
|
83
|
+
index_together = (("score",),) # Qidiruvni tezlashtirish uchun index
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. CRUD (Yaratish, O'qish, Yangilash, O'chirish)
|
|
87
|
+
|
|
88
|
+
**Sinxron:**
|
|
89
|
+
```python
|
|
90
|
+
# Yaratish
|
|
91
|
+
user = User.create(name="Ali", age=25)
|
|
92
|
+
|
|
93
|
+
# Barchasini olish
|
|
94
|
+
users = User.all()
|
|
95
|
+
|
|
96
|
+
# Qidirish
|
|
97
|
+
user = User.query().filter(name="Ali").first()
|
|
98
|
+
|
|
99
|
+
# Yangilash
|
|
100
|
+
user.score = 99.5
|
|
101
|
+
user.save()
|
|
102
|
+
|
|
103
|
+
# O'chirish
|
|
104
|
+
user.delete()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Asinxron:**
|
|
108
|
+
```python
|
|
109
|
+
# Yaratish
|
|
110
|
+
user = await AsyncUser.create(name="Vali", age=22)
|
|
111
|
+
|
|
112
|
+
# Barchasini olish
|
|
113
|
+
users = await AsyncUser.all()
|
|
114
|
+
|
|
115
|
+
# Qidirish
|
|
116
|
+
user = await AsyncUser.query().filter(name="Vali").first()
|
|
117
|
+
|
|
118
|
+
# Yangilash
|
|
119
|
+
user.score = 100.0
|
|
120
|
+
await user.save()
|
|
121
|
+
|
|
122
|
+
# O'chirish
|
|
123
|
+
await user.delete()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 4. Raw SQL dan Model Olish
|
|
127
|
+
Ba'zida juda murakkab yoki spesifik SQL yozishga to'g'ri keladi. Shunday paytda u oddiy `dict` emas, to'g'ridan to'g'ri Model obyekti bo'lib qaytishi kerak:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
# Sinxron
|
|
131
|
+
users = User.raw_sql("SELECT * FROM users WHERE age > %s", 20)
|
|
132
|
+
print(users[0].name) # Bu Model Obyekti!
|
|
133
|
+
|
|
134
|
+
# Asinxron
|
|
135
|
+
users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > $1", 20)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 🔄 Migratsiya (Django uslubida)
|
|
141
|
+
|
|
142
|
+
Siz o'z loyihangiz papkasida bitta `manage.py` yaratib olib, jadvallarni SQL o'qib-o'tirmasdan terminal orqali avtomatik yangilab borishingiz mumkin.
|
|
143
|
+
|
|
144
|
+
**`manage.py` yaratamiz:**
|
|
145
|
+
```python
|
|
146
|
+
import sys
|
|
147
|
+
from postgresdb3 import execute_from_command_line
|
|
148
|
+
from myapp.models import db_sync # 1. Sizning bazaga ulangan db obyektingiz
|
|
149
|
+
|
|
150
|
+
# 2. DIQQAT: Migratsiya dvigateli modellarni ko'rishi uchun
|
|
151
|
+
# ularni albatta import qilib qo'yishingiz SHART!
|
|
152
|
+
from myapp.models import User, Post, Tag
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
execute_from_command_line(db_sync, sys.argv)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Terminalda:**
|
|
159
|
+
```bash
|
|
160
|
+
# 1. Modellar asosida migratsiya faylini tayyorlash
|
|
161
|
+
python manage.py makemigrations initial_setup
|
|
162
|
+
|
|
163
|
+
# 2. Bazaga jadvallarni qo'shish
|
|
164
|
+
python manage.py migrate
|
|
165
|
+
|
|
166
|
+
# 3. Oxirgi migratsiyani bekor qilish va qaytarish (Rollback)
|
|
167
|
+
python manage.py undo
|
|
168
|
+
```
|
|
169
|
+
*Tizim jadval qo'shish, ustunlarni o'zgartirish va `Meta` klassidagi indekslarni avtomatik o'zi hal qiladi! Xato qilsangiz, `undo` orqali bir soniyada hammasini orqaga qaytara olasiz.*
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🔍 Murakkab Qidiruv va Filtrlar (Q va F)
|
|
174
|
+
|
|
175
|
+
**Q Obyekti (Murakkab shartlar - AND, OR):**
|
|
176
|
+
```python
|
|
177
|
+
from postgresdb3 import Q
|
|
178
|
+
|
|
179
|
+
# OR (|) sharti
|
|
180
|
+
users = User.query().filter(Q(age__gt=20) | Q(name="Ali")).all()
|
|
181
|
+
|
|
182
|
+
# AND (&) sharti
|
|
183
|
+
users = User.query().filter(Q(age__lt=30) & Q(score__gt=50)).all()
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**F Obyekti (Ustunlarni bir-biriga solishtirish yoki yangilash):**
|
|
187
|
+
```python
|
|
188
|
+
from postgresdb3 import F
|
|
189
|
+
|
|
190
|
+
# Yoshiga nisbatan score'i katta bo'lganlarni izlash
|
|
191
|
+
users = User.query().filter(score__gt=F("age")).all()
|
|
192
|
+
|
|
193
|
+
# Barchaning balini bazaning o'zida +10 ga oshirish
|
|
194
|
+
User.query().update(score=F("score") + 10)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 🔗 Aloqalar (Relations) va N+1 Yechimi
|
|
200
|
+
|
|
201
|
+
Loyiha `ForeignKey`, `OneToOneField` va `ManyToManyField` kabi turlarni to'liq qo'llab-quvvatlaydi.
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from postgresdb3 import ForeignKey, ManyToManyField
|
|
205
|
+
|
|
206
|
+
class Post(Model):
|
|
207
|
+
title = String(length=100)
|
|
208
|
+
author = ForeignKey(User, related_name="posts")
|
|
209
|
+
|
|
210
|
+
class Tag(Model):
|
|
211
|
+
name = String(length=50)
|
|
212
|
+
posts = ManyToManyField(Post, related_name="tags")
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**N+1 xatoligini chetlab o'tish:**
|
|
216
|
+
Odatda chet el kalitlari bilan ishlaganda ko'plab ortiqcha so'rovlar yuzaga keladi. Bunga qarshi quyidagilardan foydalaning:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
# ForeignKey uchun
|
|
220
|
+
posts = Post.query().select_related("author").all()
|
|
221
|
+
print(posts[0].author.name) # 1 ta SQL query bilan ish bitadi
|
|
222
|
+
|
|
223
|
+
# ManyToMany uchun
|
|
224
|
+
posts = Post.query().prefetch_related("tags").all()
|
|
225
|
+
for p in posts:
|
|
226
|
+
print(p.tags) # N+1 muammosi bo'lmaydi
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 📊 Katta Ma'lumotlar bilan Ishlash (Bulk & Pagination)
|
|
232
|
+
|
|
233
|
+
**Ommaviy Yozish (Bulk Create):**
|
|
234
|
+
10,000 ta obyekti birma-bir emas, bitta so'rov orqali kiritish:
|
|
235
|
+
```python
|
|
236
|
+
users = [User(name=f"U-{i}", age=20) for i in range(10000)]
|
|
237
|
+
User.bulk_create(users)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Ommaviy Yangilash (Bulk Update):**
|
|
241
|
+
```python
|
|
242
|
+
users = User.all()
|
|
243
|
+
for u in users:
|
|
244
|
+
u.age += 1
|
|
245
|
+
User.bulk_update(users, fields=["age"])
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Sahifalash (Pagination):**
|
|
249
|
+
Foydalanuvchiga ma'lumotlarni qismlab (limit/offset bilan avtomatik) taqdim etish:
|
|
250
|
+
```python
|
|
251
|
+
result = User.query().paginate(page=1, per_page=20)
|
|
252
|
+
print(result["total"]) # Jami elementlar soni
|
|
253
|
+
print(result["pages"]) # Jami sahifalar soni
|
|
254
|
+
print(result["has_next"]) # Keyingi sahifa bormi? (True/False)
|
|
255
|
+
print(result["data"]) # Modellar ro'yxati (20 ta)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 🛡 Tranzaksiyalar (Xavfsizlik)
|
|
261
|
+
|
|
262
|
+
Muhim operatsiyalar (masalan, pul o'tkazish) vaqtida xato yuz bersa, barcha qilingan ishlarni avtomatik bekor qilish (Rollback):
|
|
263
|
+
|
|
264
|
+
**Sinxron:**
|
|
265
|
+
```python
|
|
266
|
+
with db_sync.transaction():
|
|
267
|
+
user1.score -= 50
|
|
268
|
+
user1.save()
|
|
269
|
+
user2.score += 50
|
|
270
|
+
user2.save()
|
|
271
|
+
# Agar shu joyda qandaydir xatolik chiqsa, hech qaysi userning puli yechilmaydi!
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Asinxron:**
|
|
275
|
+
```python
|
|
276
|
+
async with db_async.transaction():
|
|
277
|
+
user1.score -= 50
|
|
278
|
+
await user1.save()
|
|
279
|
+
user2.score += 50
|
|
280
|
+
await user2.save()
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 📈 Agregatsiya (Sum, Avg, Min, Max, Count)
|
|
286
|
+
|
|
287
|
+
Baza orqali kalkulyatsiyalarni amalga oshirish:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
from postgresdb3 import Sum, Avg, Max
|
|
291
|
+
|
|
292
|
+
result = User.query().aggregate(
|
|
293
|
+
total_score=Sum("score"),
|
|
294
|
+
avg_age=Avg("age"),
|
|
295
|
+
max_score=Max("score")
|
|
296
|
+
)
|
|
297
|
+
print(result) # {'total_score': 1500, 'avg_age': 25, 'max_score': 100}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
*Ushbu ORM kutubxonasi tezlik va xavfsizlikni birinchi o'ringa qoyuvchi mutaxassislar uchun maxsus qurilgan. Mazza qilib foydalaning!*
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# PostgresDB3 - High-Performance Python ORM
|
|
2
|
+
|
|
3
|
+
**PostgresDB3** — bu PostgreSQL uchun mo'ljallangan zamonaviy, tezkor va ham **sinxron**, ham **asinxron** ishlash imkoniyatiga ega bo'lgan ORM (Object-Relational Mapping) kutubxonasi.
|
|
4
|
+
|
|
5
|
+
U Django ORM kabi qulay va oson tushuniladi, lekin o'zida asinxronlik (`asyncpg`) va ko'plab yuqori texnologik xususiyatlarni mujassamlashtirgan. Kichik botlardan tortib, o'ta katta masshtabdagi (Highload) loyihalargacha bemalol ishlata olasiz!
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📦 O'rnatish
|
|
10
|
+
|
|
11
|
+
Kutubxonani o'rnatish uchun terminalda quyidagi buyruqni kiriting:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install postgresdb3
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🚀 Tezkor Boshlash
|
|
20
|
+
|
|
21
|
+
PostgresDB3 bir vaqtning o'zida ikkita dunyoni qo'llab-quvvatlaydi. Xohlasangiz **Sinxron**, xohlasangiz **Asinxron** loyihalarda bir xil sintaksis bilan ishlay olasiz.
|
|
22
|
+
|
|
23
|
+
### 1. Ulanishni sozlash
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from postgresdb3 import PostgresDB, AsyncPostgresDB
|
|
27
|
+
|
|
28
|
+
# Sinxron ulanish (psycopg2 asosida)
|
|
29
|
+
db_sync = PostgresDB("my_db", "user", "password", host="localhost", port=5432, echo=True)
|
|
30
|
+
|
|
31
|
+
# Asinxron ulanish (asyncpg asosida)
|
|
32
|
+
db_async = AsyncPostgresDB("my_db", "user", "password", host="localhost", port=5432, echo=True)
|
|
33
|
+
```
|
|
34
|
+
*(Eslatma: `echo=True` yoqilsa, barcha bajarilayotgan SQL so'rovlar terminalda ko'rinib turadi, bu debug uchun juda foydali).*
|
|
35
|
+
|
|
36
|
+
### 2. Modellarni Yaratish
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from postgresdb3.orm.models import Model, AsyncModel
|
|
40
|
+
from postgresdb3 import String, Integer, Float
|
|
41
|
+
|
|
42
|
+
# Sinxron model
|
|
43
|
+
Model.db = db_sync
|
|
44
|
+
|
|
45
|
+
class User(Model):
|
|
46
|
+
name = String(length=50)
|
|
47
|
+
age = Integer(default=18)
|
|
48
|
+
score = Float(default=0.0)
|
|
49
|
+
|
|
50
|
+
# Asinxron model
|
|
51
|
+
AsyncModel.db = db_async
|
|
52
|
+
|
|
53
|
+
class AsyncUser(AsyncModel):
|
|
54
|
+
name = String(length=50)
|
|
55
|
+
age = Integer(default=18)
|
|
56
|
+
score = Float(default=0.0)
|
|
57
|
+
|
|
58
|
+
# Qo'shimcha sozlamalar (Murakkab Indekslar)
|
|
59
|
+
class Meta:
|
|
60
|
+
unique_together = (("name", "age"),) # Ism va yosh bir xil takrorlanmasligi kerak
|
|
61
|
+
index_together = (("score",),) # Qidiruvni tezlashtirish uchun index
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. CRUD (Yaratish, O'qish, Yangilash, O'chirish)
|
|
65
|
+
|
|
66
|
+
**Sinxron:**
|
|
67
|
+
```python
|
|
68
|
+
# Yaratish
|
|
69
|
+
user = User.create(name="Ali", age=25)
|
|
70
|
+
|
|
71
|
+
# Barchasini olish
|
|
72
|
+
users = User.all()
|
|
73
|
+
|
|
74
|
+
# Qidirish
|
|
75
|
+
user = User.query().filter(name="Ali").first()
|
|
76
|
+
|
|
77
|
+
# Yangilash
|
|
78
|
+
user.score = 99.5
|
|
79
|
+
user.save()
|
|
80
|
+
|
|
81
|
+
# O'chirish
|
|
82
|
+
user.delete()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Asinxron:**
|
|
86
|
+
```python
|
|
87
|
+
# Yaratish
|
|
88
|
+
user = await AsyncUser.create(name="Vali", age=22)
|
|
89
|
+
|
|
90
|
+
# Barchasini olish
|
|
91
|
+
users = await AsyncUser.all()
|
|
92
|
+
|
|
93
|
+
# Qidirish
|
|
94
|
+
user = await AsyncUser.query().filter(name="Vali").first()
|
|
95
|
+
|
|
96
|
+
# Yangilash
|
|
97
|
+
user.score = 100.0
|
|
98
|
+
await user.save()
|
|
99
|
+
|
|
100
|
+
# O'chirish
|
|
101
|
+
await user.delete()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 4. Raw SQL dan Model Olish
|
|
105
|
+
Ba'zida juda murakkab yoki spesifik SQL yozishga to'g'ri keladi. Shunday paytda u oddiy `dict` emas, to'g'ridan to'g'ri Model obyekti bo'lib qaytishi kerak:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# Sinxron
|
|
109
|
+
users = User.raw_sql("SELECT * FROM users WHERE age > %s", 20)
|
|
110
|
+
print(users[0].name) # Bu Model Obyekti!
|
|
111
|
+
|
|
112
|
+
# Asinxron
|
|
113
|
+
users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > $1", 20)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 🔄 Migratsiya (Django uslubida)
|
|
119
|
+
|
|
120
|
+
Siz o'z loyihangiz papkasida bitta `manage.py` yaratib olib, jadvallarni SQL o'qib-o'tirmasdan terminal orqali avtomatik yangilab borishingiz mumkin.
|
|
121
|
+
|
|
122
|
+
**`manage.py` yaratamiz:**
|
|
123
|
+
```python
|
|
124
|
+
import sys
|
|
125
|
+
from postgresdb3 import execute_from_command_line
|
|
126
|
+
from myapp.models import db_sync # 1. Sizning bazaga ulangan db obyektingiz
|
|
127
|
+
|
|
128
|
+
# 2. DIQQAT: Migratsiya dvigateli modellarni ko'rishi uchun
|
|
129
|
+
# ularni albatta import qilib qo'yishingiz SHART!
|
|
130
|
+
from myapp.models import User, Post, Tag
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
execute_from_command_line(db_sync, sys.argv)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Terminalda:**
|
|
137
|
+
```bash
|
|
138
|
+
# 1. Modellar asosida migratsiya faylini tayyorlash
|
|
139
|
+
python manage.py makemigrations initial_setup
|
|
140
|
+
|
|
141
|
+
# 2. Bazaga jadvallarni qo'shish
|
|
142
|
+
python manage.py migrate
|
|
143
|
+
|
|
144
|
+
# 3. Oxirgi migratsiyani bekor qilish va qaytarish (Rollback)
|
|
145
|
+
python manage.py undo
|
|
146
|
+
```
|
|
147
|
+
*Tizim jadval qo'shish, ustunlarni o'zgartirish va `Meta` klassidagi indekslarni avtomatik o'zi hal qiladi! Xato qilsangiz, `undo` orqali bir soniyada hammasini orqaga qaytara olasiz.*
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🔍 Murakkab Qidiruv va Filtrlar (Q va F)
|
|
152
|
+
|
|
153
|
+
**Q Obyekti (Murakkab shartlar - AND, OR):**
|
|
154
|
+
```python
|
|
155
|
+
from postgresdb3 import Q
|
|
156
|
+
|
|
157
|
+
# OR (|) sharti
|
|
158
|
+
users = User.query().filter(Q(age__gt=20) | Q(name="Ali")).all()
|
|
159
|
+
|
|
160
|
+
# AND (&) sharti
|
|
161
|
+
users = User.query().filter(Q(age__lt=30) & Q(score__gt=50)).all()
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**F Obyekti (Ustunlarni bir-biriga solishtirish yoki yangilash):**
|
|
165
|
+
```python
|
|
166
|
+
from postgresdb3 import F
|
|
167
|
+
|
|
168
|
+
# Yoshiga nisbatan score'i katta bo'lganlarni izlash
|
|
169
|
+
users = User.query().filter(score__gt=F("age")).all()
|
|
170
|
+
|
|
171
|
+
# Barchaning balini bazaning o'zida +10 ga oshirish
|
|
172
|
+
User.query().update(score=F("score") + 10)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🔗 Aloqalar (Relations) va N+1 Yechimi
|
|
178
|
+
|
|
179
|
+
Loyiha `ForeignKey`, `OneToOneField` va `ManyToManyField` kabi turlarni to'liq qo'llab-quvvatlaydi.
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from postgresdb3 import ForeignKey, ManyToManyField
|
|
183
|
+
|
|
184
|
+
class Post(Model):
|
|
185
|
+
title = String(length=100)
|
|
186
|
+
author = ForeignKey(User, related_name="posts")
|
|
187
|
+
|
|
188
|
+
class Tag(Model):
|
|
189
|
+
name = String(length=50)
|
|
190
|
+
posts = ManyToManyField(Post, related_name="tags")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**N+1 xatoligini chetlab o'tish:**
|
|
194
|
+
Odatda chet el kalitlari bilan ishlaganda ko'plab ortiqcha so'rovlar yuzaga keladi. Bunga qarshi quyidagilardan foydalaning:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
# ForeignKey uchun
|
|
198
|
+
posts = Post.query().select_related("author").all()
|
|
199
|
+
print(posts[0].author.name) # 1 ta SQL query bilan ish bitadi
|
|
200
|
+
|
|
201
|
+
# ManyToMany uchun
|
|
202
|
+
posts = Post.query().prefetch_related("tags").all()
|
|
203
|
+
for p in posts:
|
|
204
|
+
print(p.tags) # N+1 muammosi bo'lmaydi
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 📊 Katta Ma'lumotlar bilan Ishlash (Bulk & Pagination)
|
|
210
|
+
|
|
211
|
+
**Ommaviy Yozish (Bulk Create):**
|
|
212
|
+
10,000 ta obyekti birma-bir emas, bitta so'rov orqali kiritish:
|
|
213
|
+
```python
|
|
214
|
+
users = [User(name=f"U-{i}", age=20) for i in range(10000)]
|
|
215
|
+
User.bulk_create(users)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Ommaviy Yangilash (Bulk Update):**
|
|
219
|
+
```python
|
|
220
|
+
users = User.all()
|
|
221
|
+
for u in users:
|
|
222
|
+
u.age += 1
|
|
223
|
+
User.bulk_update(users, fields=["age"])
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Sahifalash (Pagination):**
|
|
227
|
+
Foydalanuvchiga ma'lumotlarni qismlab (limit/offset bilan avtomatik) taqdim etish:
|
|
228
|
+
```python
|
|
229
|
+
result = User.query().paginate(page=1, per_page=20)
|
|
230
|
+
print(result["total"]) # Jami elementlar soni
|
|
231
|
+
print(result["pages"]) # Jami sahifalar soni
|
|
232
|
+
print(result["has_next"]) # Keyingi sahifa bormi? (True/False)
|
|
233
|
+
print(result["data"]) # Modellar ro'yxati (20 ta)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 🛡 Tranzaksiyalar (Xavfsizlik)
|
|
239
|
+
|
|
240
|
+
Muhim operatsiyalar (masalan, pul o'tkazish) vaqtida xato yuz bersa, barcha qilingan ishlarni avtomatik bekor qilish (Rollback):
|
|
241
|
+
|
|
242
|
+
**Sinxron:**
|
|
243
|
+
```python
|
|
244
|
+
with db_sync.transaction():
|
|
245
|
+
user1.score -= 50
|
|
246
|
+
user1.save()
|
|
247
|
+
user2.score += 50
|
|
248
|
+
user2.save()
|
|
249
|
+
# Agar shu joyda qandaydir xatolik chiqsa, hech qaysi userning puli yechilmaydi!
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Asinxron:**
|
|
253
|
+
```python
|
|
254
|
+
async with db_async.transaction():
|
|
255
|
+
user1.score -= 50
|
|
256
|
+
await user1.save()
|
|
257
|
+
user2.score += 50
|
|
258
|
+
await user2.save()
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 📈 Agregatsiya (Sum, Avg, Min, Max, Count)
|
|
264
|
+
|
|
265
|
+
Baza orqali kalkulyatsiyalarni amalga oshirish:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from postgresdb3 import Sum, Avg, Max
|
|
269
|
+
|
|
270
|
+
result = User.query().aggregate(
|
|
271
|
+
total_score=Sum("score"),
|
|
272
|
+
avg_age=Avg("age"),
|
|
273
|
+
max_score=Max("score")
|
|
274
|
+
)
|
|
275
|
+
print(result) # {'total_score': 1500, 'avg_age': 25, 'max_score': 100}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
*Ushbu ORM kutubxonasi tezlik va xavfsizlikni birinchi o'ringa qoyuvchi mutaxassislar uchun maxsus qurilgan. Mazza qilib foydalaning!*
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .core import PostgresDB, AsyncPostgresDB
|
|
2
|
+
from .migrations.engine import MigrationEngine
|
|
3
|
+
from .orm.expressions import Q, F, Sum, Avg, Min, Max, Count
|
|
4
|
+
from .orm.fields import (
|
|
5
|
+
String, Integer, Boolean, Float, Double, Decimal,
|
|
6
|
+
Date, Time, Timestamp, Timestamptz,
|
|
7
|
+
JSON, JSONB, UUID, Array,
|
|
8
|
+
ForeignKey, OneToOneField, ManyToManyField,
|
|
9
|
+
Serial, BigSerial, SmallInteger, BigInteger, Text
|
|
10
|
+
)
|
|
11
|
+
from .cli import execute_from_command_line
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import argparse
|
|
3
|
+
import asyncio
|
|
4
|
+
from .migrations.engine import MigrationEngine
|
|
5
|
+
from .core import PostgresDB, AsyncPostgresDB
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def execute_from_command_line(db, argv=None):
|
|
9
|
+
"""
|
|
10
|
+
Kutubxonadan foydalanuvchilar o'z loyihalarida terminal buyruqlarini
|
|
11
|
+
ishga tushirishi uchun maxsus CLI funksiyasi (xuddi Django manage.py kabi).
|
|
12
|
+
"""
|
|
13
|
+
if argv is None:
|
|
14
|
+
argv = sys.argv
|
|
15
|
+
|
|
16
|
+
parser = argparse.ArgumentParser(description="PostgresDB CLI - Ma'lumotlar bazasini boshqarish")
|
|
17
|
+
subparsers = parser.add_subparsers(dest="command", help="Mavjud buyruqlar")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
make_parser = subparsers.add_parser("makemigrations", help="Modellardagi o'zgarishlar asosida yangi migratsiya fayllarini yaratadi")
|
|
21
|
+
make_parser.add_argument("name", nargs="?", default="auto", help="Migratsiya nomi (masalan: initial_setup)")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
subparsers.add_parser("migrate", help="Mavjud migratsiyalarni ma'lumotlar bazasiga qo'llaydi")
|
|
25
|
+
subparsers.add_parser("undo", help="Oxirgi migratsiyani bekor qiladi va bazadan o'chiradi")
|
|
26
|
+
|
|
27
|
+
args = parser.parse_args(argv[1:])
|
|
28
|
+
|
|
29
|
+
if args.command == "makemigrations":
|
|
30
|
+
engine = MigrationEngine()
|
|
31
|
+
print(f"'{args.name}' nomli migratsiya yaratilmoqda...")
|
|
32
|
+
engine.makemigrations(args.name)
|
|
33
|
+
|
|
34
|
+
elif args.command == "migrate":
|
|
35
|
+
engine = MigrationEngine()
|
|
36
|
+
if isinstance(db, PostgresDB):
|
|
37
|
+
engine.migrate(db)
|
|
38
|
+
elif isinstance(db, AsyncPostgresDB):
|
|
39
|
+
|
|
40
|
+
loop = asyncio.get_event_loop()
|
|
41
|
+
if loop.is_running():
|
|
42
|
+
asyncio.ensure_future(engine.async_migrate(db))
|
|
43
|
+
else:
|
|
44
|
+
loop.run_until_complete(engine.async_migrate(db))
|
|
45
|
+
else:
|
|
46
|
+
print("Xato: Noma'lum DB obyekti (PostgresDB yoki AsyncPostgresDB kerak).")
|
|
47
|
+
|
|
48
|
+
elif args.command == "undo":
|
|
49
|
+
engine = MigrationEngine()
|
|
50
|
+
if isinstance(db, PostgresDB):
|
|
51
|
+
engine.undo_migration(db)
|
|
52
|
+
elif isinstance(db, AsyncPostgresDB):
|
|
53
|
+
loop = asyncio.get_event_loop()
|
|
54
|
+
if loop.is_running():
|
|
55
|
+
asyncio.ensure_future(engine.async_undo_migration(db))
|
|
56
|
+
else:
|
|
57
|
+
loop.run_until_complete(engine.async_undo_migration(db))
|
|
58
|
+
else:
|
|
59
|
+
print("Xato: Noma'lum DB obyekti (PostgresDB yoki AsyncPostgresDB kerak).")
|
|
60
|
+
|
|
61
|
+
else:
|
|
62
|
+
parser.print_help()
|