af-db-teach 0.1.0__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.
- af_db_teach-0.1.0/LICENSE +6 -0
- af_db_teach-0.1.0/MANIFEST.in +0 -0
- af_db_teach-0.1.0/PKG-INFO +198 -0
- af_db_teach-0.1.0/README.md +176 -0
- af_db_teach-0.1.0/af_db_teach/__init__.py +6 -0
- af_db_teach-0.1.0/af_db_teach/keywords.py +2 -0
- af_db_teach-0.1.0/af_db_teach/model.py +101 -0
- af_db_teach-0.1.0/af_db_teach/table_base.py +38 -0
- af_db_teach-0.1.0/af_db_teach.egg-info/PKG-INFO +198 -0
- af_db_teach-0.1.0/af_db_teach.egg-info/SOURCES.txt +13 -0
- af_db_teach-0.1.0/af_db_teach.egg-info/dependency_links.txt +1 -0
- af_db_teach-0.1.0/af_db_teach.egg-info/top_level.txt +1 -0
- af_db_teach-0.1.0/pyproject.toml +24 -0
- af_db_teach-0.1.0/setup.cfg +4 -0
- af_db_teach-0.1.0/setup.py +19 -0
|
File without changes
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: af_db_teach
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Core SQLite ORM with separate educational modules
|
|
5
|
+
Home-page: https://github.com/abbasfaramarzi/af_db_teach
|
|
6
|
+
Author: Abbas Faramarzi Filabadi
|
|
7
|
+
Author-email: Abbas Faramarzi Filabadi <abbasfaramarzi@068gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
Project-URL: Homepage, https://github.com/abbasfaramarzi/af_db_teach
|
|
10
|
+
Project-URL: Bug Reports, https://github.com/abbasfaramarzi/af_db_teach/issues
|
|
11
|
+
Project-URL: Source, https://github.com/abbasfaramarzi/af_db_teach
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
# af_db_teach
|
|
25
|
+
|
|
26
|
+
A simple, educational ORM for SQLite in Python.
|
|
27
|
+
This package allows you to work with an SQLite database without writing raw SQL queries.
|
|
28
|
+
Designed for small projects and learning ORM concepts.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- Define models using Python classes and simple attributes
|
|
33
|
+
- Automatic CRUD operations (Create, Read, Update, Delete)
|
|
34
|
+
- Automatic table management (create, update schema, drop)
|
|
35
|
+
- Support for default data (`_default_data`)
|
|
36
|
+
- Helper methods like search, borrow/return (in the library example)
|
|
37
|
+
- Export all tables and data as a dictionary with `db_deeep_interface`
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install af_db_teach
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> **Note:** This package will be published on PyPI soon. You can also use it directly from the GitHub repository.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
### 1. Define a Model
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from af_db_teach import Model
|
|
53
|
+
|
|
54
|
+
class Product(Model):
|
|
55
|
+
_primary_key = "id"
|
|
56
|
+
id = 0
|
|
57
|
+
name = ""
|
|
58
|
+
price = 0.0
|
|
59
|
+
in_stock = 1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- The table name is automatically derived from the class name (lowercase): `product`
|
|
63
|
+
- Fields are defined as class attributes.
|
|
64
|
+
- Data types (INTEGER, REAL, TEXT) are inferred from the example values (`int`, `float`, `str`).
|
|
65
|
+
|
|
66
|
+
### 2. Work with the Database
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Connect and create the table
|
|
70
|
+
db = Product("shop.db")
|
|
71
|
+
|
|
72
|
+
# Insert a row
|
|
73
|
+
new_id = db.insert_one(name="Python Book", price=25000, in_stock=1)
|
|
74
|
+
|
|
75
|
+
# Get all records
|
|
76
|
+
all_products = db.get_all()
|
|
77
|
+
|
|
78
|
+
# Get a single record by primary key
|
|
79
|
+
product = db.get_one(1)
|
|
80
|
+
|
|
81
|
+
# Update a record
|
|
82
|
+
db.update(1, price=27000)
|
|
83
|
+
|
|
84
|
+
# Delete a record
|
|
85
|
+
db.delete(1)
|
|
86
|
+
|
|
87
|
+
# Drop the entire table
|
|
88
|
+
db.delete_table()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Default Data
|
|
92
|
+
|
|
93
|
+
You can define `_default_data` in your model class to insert initial records:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
class Category(Model):
|
|
97
|
+
id = 0
|
|
98
|
+
title = ""
|
|
99
|
+
|
|
100
|
+
_default_data = [
|
|
101
|
+
(1, "Electronics"),
|
|
102
|
+
(2, "Books"),
|
|
103
|
+
(3, "Clothing"),
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> Note: The order of values must match the order of fields returned by `table_fields()`.
|
|
108
|
+
|
|
109
|
+
## Model Methods
|
|
110
|
+
|
|
111
|
+
| Method | Description |
|
|
112
|
+
|--------|-------------|
|
|
113
|
+
| `insert_one(**kwargs)` | Insert a new row. Returns `lastrowid`. |
|
|
114
|
+
| `get_all(where="", params=())` | Get all rows (optional WHERE clause). |
|
|
115
|
+
| `get_one(row_id)` | Get a single row by primary key. |
|
|
116
|
+
| `update(row_id, **kwargs)` | Update specified fields. |
|
|
117
|
+
| `delete(row_id)` | Delete a row by primary key. |
|
|
118
|
+
| `delete_table(table_name=None)` | Drop the entire table. |
|
|
119
|
+
| `db_deeep_interface()` | Return a dictionary of all tables and their contents. |
|
|
120
|
+
|
|
121
|
+
## Complete Example: Library Management
|
|
122
|
+
|
|
123
|
+
The file `library_orm_demo.py` provides a practical library system example:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from af_db_teach import Model
|
|
127
|
+
from datetime import date
|
|
128
|
+
|
|
129
|
+
class Book(Model):
|
|
130
|
+
_primary_key = "id"
|
|
131
|
+
id = 0
|
|
132
|
+
title = ""
|
|
133
|
+
author = ""
|
|
134
|
+
year = 2000
|
|
135
|
+
is_available = 1
|
|
136
|
+
|
|
137
|
+
def borrow(self, book_id):
|
|
138
|
+
book = self.get_one(book_id)
|
|
139
|
+
if book and book['is_available'] == 1:
|
|
140
|
+
return self.update(book_id, is_available=0)
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
def return_book(self, book_id):
|
|
144
|
+
book = self.get_one(book_id)
|
|
145
|
+
if book and book['is_available'] == 0:
|
|
146
|
+
return self.update(book_id, is_available=1)
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
# Usage
|
|
150
|
+
book_db = Book("library.db")
|
|
151
|
+
book_db.insert_one(title="Thus Spoke Zarathustra", author="Nietzsche", year=1885)
|
|
152
|
+
book_db.borrow(1) # borrow the book
|
|
153
|
+
book_db.return_book(1) # return it
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Run the full demo:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
python library_orm_demo.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Advanced Notes
|
|
163
|
+
|
|
164
|
+
### 1. Ignoring a Table
|
|
165
|
+
|
|
166
|
+
The `Keywords` class contains a list `ignores_table_name_list`. If a table name is in this list, `create_table` will not create it. You can extend this list:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from af_db_teach import Keywords
|
|
170
|
+
Keywords.ignores_table_name_list.append("my_temp_table")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 2. Base Class `TableBase`
|
|
174
|
+
|
|
175
|
+
If you need a model without direct database connection (just the table structure), you can inherit from `TableBase`.
|
|
176
|
+
|
|
177
|
+
### 3. Connecting to an Existing Database
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
db = Model("my_database.db")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
If the database file does not exist, it will be created.
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
This project is released under the MIT License.
|
|
188
|
+
|
|
189
|
+
## Author
|
|
190
|
+
|
|
191
|
+
Abbas Faramarzi
|
|
192
|
+
[Email](mailto:abbasfaramarzi@068gmail.com)
|
|
193
|
+
[GitHub Repository](https://github.com/abbasfaramarzi/af_db_teach)
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
**af_db_teach** – A simple tool for learning and using ORM in small Python projects.
|
|
198
|
+
```
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
```markdown
|
|
2
|
+
# af_db_teach
|
|
3
|
+
|
|
4
|
+
A simple, educational ORM for SQLite in Python.
|
|
5
|
+
This package allows you to work with an SQLite database without writing raw SQL queries.
|
|
6
|
+
Designed for small projects and learning ORM concepts.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Define models using Python classes and simple attributes
|
|
11
|
+
- Automatic CRUD operations (Create, Read, Update, Delete)
|
|
12
|
+
- Automatic table management (create, update schema, drop)
|
|
13
|
+
- Support for default data (`_default_data`)
|
|
14
|
+
- Helper methods like search, borrow/return (in the library example)
|
|
15
|
+
- Export all tables and data as a dictionary with `db_deeep_interface`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install af_db_teach
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> **Note:** This package will be published on PyPI soon. You can also use it directly from the GitHub repository.
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### 1. Define a Model
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from af_db_teach import Model
|
|
31
|
+
|
|
32
|
+
class Product(Model):
|
|
33
|
+
_primary_key = "id"
|
|
34
|
+
id = 0
|
|
35
|
+
name = ""
|
|
36
|
+
price = 0.0
|
|
37
|
+
in_stock = 1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- The table name is automatically derived from the class name (lowercase): `product`
|
|
41
|
+
- Fields are defined as class attributes.
|
|
42
|
+
- Data types (INTEGER, REAL, TEXT) are inferred from the example values (`int`, `float`, `str`).
|
|
43
|
+
|
|
44
|
+
### 2. Work with the Database
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# Connect and create the table
|
|
48
|
+
db = Product("shop.db")
|
|
49
|
+
|
|
50
|
+
# Insert a row
|
|
51
|
+
new_id = db.insert_one(name="Python Book", price=25000, in_stock=1)
|
|
52
|
+
|
|
53
|
+
# Get all records
|
|
54
|
+
all_products = db.get_all()
|
|
55
|
+
|
|
56
|
+
# Get a single record by primary key
|
|
57
|
+
product = db.get_one(1)
|
|
58
|
+
|
|
59
|
+
# Update a record
|
|
60
|
+
db.update(1, price=27000)
|
|
61
|
+
|
|
62
|
+
# Delete a record
|
|
63
|
+
db.delete(1)
|
|
64
|
+
|
|
65
|
+
# Drop the entire table
|
|
66
|
+
db.delete_table()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. Default Data
|
|
70
|
+
|
|
71
|
+
You can define `_default_data` in your model class to insert initial records:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
class Category(Model):
|
|
75
|
+
id = 0
|
|
76
|
+
title = ""
|
|
77
|
+
|
|
78
|
+
_default_data = [
|
|
79
|
+
(1, "Electronics"),
|
|
80
|
+
(2, "Books"),
|
|
81
|
+
(3, "Clothing"),
|
|
82
|
+
]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
> Note: The order of values must match the order of fields returned by `table_fields()`.
|
|
86
|
+
|
|
87
|
+
## Model Methods
|
|
88
|
+
|
|
89
|
+
| Method | Description |
|
|
90
|
+
|--------|-------------|
|
|
91
|
+
| `insert_one(**kwargs)` | Insert a new row. Returns `lastrowid`. |
|
|
92
|
+
| `get_all(where="", params=())` | Get all rows (optional WHERE clause). |
|
|
93
|
+
| `get_one(row_id)` | Get a single row by primary key. |
|
|
94
|
+
| `update(row_id, **kwargs)` | Update specified fields. |
|
|
95
|
+
| `delete(row_id)` | Delete a row by primary key. |
|
|
96
|
+
| `delete_table(table_name=None)` | Drop the entire table. |
|
|
97
|
+
| `db_deeep_interface()` | Return a dictionary of all tables and their contents. |
|
|
98
|
+
|
|
99
|
+
## Complete Example: Library Management
|
|
100
|
+
|
|
101
|
+
The file `library_orm_demo.py` provides a practical library system example:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from af_db_teach import Model
|
|
105
|
+
from datetime import date
|
|
106
|
+
|
|
107
|
+
class Book(Model):
|
|
108
|
+
_primary_key = "id"
|
|
109
|
+
id = 0
|
|
110
|
+
title = ""
|
|
111
|
+
author = ""
|
|
112
|
+
year = 2000
|
|
113
|
+
is_available = 1
|
|
114
|
+
|
|
115
|
+
def borrow(self, book_id):
|
|
116
|
+
book = self.get_one(book_id)
|
|
117
|
+
if book and book['is_available'] == 1:
|
|
118
|
+
return self.update(book_id, is_available=0)
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
def return_book(self, book_id):
|
|
122
|
+
book = self.get_one(book_id)
|
|
123
|
+
if book and book['is_available'] == 0:
|
|
124
|
+
return self.update(book_id, is_available=1)
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
# Usage
|
|
128
|
+
book_db = Book("library.db")
|
|
129
|
+
book_db.insert_one(title="Thus Spoke Zarathustra", author="Nietzsche", year=1885)
|
|
130
|
+
book_db.borrow(1) # borrow the book
|
|
131
|
+
book_db.return_book(1) # return it
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Run the full demo:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python library_orm_demo.py
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Advanced Notes
|
|
141
|
+
|
|
142
|
+
### 1. Ignoring a Table
|
|
143
|
+
|
|
144
|
+
The `Keywords` class contains a list `ignores_table_name_list`. If a table name is in this list, `create_table` will not create it. You can extend this list:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from af_db_teach import Keywords
|
|
148
|
+
Keywords.ignores_table_name_list.append("my_temp_table")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 2. Base Class `TableBase`
|
|
152
|
+
|
|
153
|
+
If you need a model without direct database connection (just the table structure), you can inherit from `TableBase`.
|
|
154
|
+
|
|
155
|
+
### 3. Connecting to an Existing Database
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
db = Model("my_database.db")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
If the database file does not exist, it will be created.
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
This project is released under the MIT License.
|
|
166
|
+
|
|
167
|
+
## Author
|
|
168
|
+
|
|
169
|
+
Abbas Faramarzi
|
|
170
|
+
[Email](mailto:abbasfaramarzi@068gmail.com)
|
|
171
|
+
[GitHub Repository](https://github.com/abbasfaramarzi/af_db_teach)
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
**af_db_teach** – A simple tool for learning and using ORM in small Python projects.
|
|
176
|
+
```
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
from typing import List, Dict, Any, Optional
|
|
3
|
+
from .keywords import Keywords
|
|
4
|
+
from .table_base import TableBase
|
|
5
|
+
|
|
6
|
+
class Model(TableBase):
|
|
7
|
+
def __init__(self, db_path="library.db"):
|
|
8
|
+
self.conn = sqlite3.connect(db_path)
|
|
9
|
+
self.conn.row_factory = sqlite3.Row
|
|
10
|
+
self.cursor = self.conn.cursor()
|
|
11
|
+
self._primary_key = "id"
|
|
12
|
+
self.create_table()
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def available_tables(self) -> List[str]:
|
|
16
|
+
return [row[0] for row in self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")]
|
|
17
|
+
|
|
18
|
+
def get_column_names(self, table_name: str) -> List[str]:
|
|
19
|
+
return [info[1] for info in self.cursor.execute(f"PRAGMA table_info({table_name})").fetchall()]
|
|
20
|
+
|
|
21
|
+
def create_table(self) -> None:
|
|
22
|
+
if self.table_name not in Keywords.ignores_table_name_list:
|
|
23
|
+
desired_fields = self.table_fields()
|
|
24
|
+
desired_sql = self._create_table_sql(primary_key=getattr(self, "_primary_key", None))
|
|
25
|
+
|
|
26
|
+
if self.table_name not in self.available_tables:
|
|
27
|
+
self.cursor.execute(desired_sql)
|
|
28
|
+
if hasattr(self.__class__, '_default_data') and self.__class__._default_data:
|
|
29
|
+
self._insert_default_data()
|
|
30
|
+
else:
|
|
31
|
+
existing_cols = self.get_column_names(self.table_name)
|
|
32
|
+
if sorted(desired_fields) != sorted(existing_cols):
|
|
33
|
+
self.delete_table(self.table_name)
|
|
34
|
+
self.cursor.execute(desired_sql)
|
|
35
|
+
if hasattr(self.__class__, '_default_data') and self.__class__._default_data:
|
|
36
|
+
self._insert_default_data()
|
|
37
|
+
self.conn.commit()
|
|
38
|
+
|
|
39
|
+
def _insert_default_data(self):
|
|
40
|
+
fields = self.table_fields()
|
|
41
|
+
placeholders = ','.join(['?'] * len(fields))
|
|
42
|
+
query = f"INSERT INTO {self.table_name} ({','.join(fields)}) VALUES ({placeholders})"
|
|
43
|
+
try:
|
|
44
|
+
self.cursor.executemany(query, self.__class__._default_data)
|
|
45
|
+
self.conn.commit()
|
|
46
|
+
except Exception as e:
|
|
47
|
+
print(f"Default data insert error: {e}")
|
|
48
|
+
|
|
49
|
+
def insert_one(self, **kwargs) -> int:
|
|
50
|
+
fields = list(kwargs.keys())
|
|
51
|
+
values = tuple(kwargs.values())
|
|
52
|
+
placeholders = ','.join(['?'] * len(fields))
|
|
53
|
+
query = f"INSERT INTO {self.table_name} ({','.join(fields)}) VALUES ({placeholders})"
|
|
54
|
+
self.cursor.execute(query, values)
|
|
55
|
+
self.conn.commit()
|
|
56
|
+
return self.cursor.lastrowid
|
|
57
|
+
|
|
58
|
+
def get_all(self, where: str = "", params: tuple = ()) -> List[Dict]:
|
|
59
|
+
query = f"SELECT * FROM {self.table_name}"
|
|
60
|
+
if where:
|
|
61
|
+
query += f" WHERE {where}"
|
|
62
|
+
rows = self.cursor.execute(query, params).fetchall()
|
|
63
|
+
return [dict(row) for row in rows]
|
|
64
|
+
|
|
65
|
+
def get_one(self, row_id: int) -> Optional[Dict]:
|
|
66
|
+
result = self.get_all(where=f"{self._primary_key}=?", params=(row_id,))
|
|
67
|
+
return result[0] if result else None
|
|
68
|
+
|
|
69
|
+
def update(self, row_id: int, **kwargs) -> bool:
|
|
70
|
+
if not kwargs:
|
|
71
|
+
return False
|
|
72
|
+
set_clause = ", ".join([f"{k}=?" for k in kwargs.keys()])
|
|
73
|
+
values = list(kwargs.values()) + [row_id]
|
|
74
|
+
query = f"UPDATE {self.table_name} SET {set_clause} WHERE {self._primary_key}=?"
|
|
75
|
+
try:
|
|
76
|
+
self.cursor.execute(query, values)
|
|
77
|
+
self.conn.commit()
|
|
78
|
+
return True
|
|
79
|
+
except Exception as e:
|
|
80
|
+
print(f"Update error: {e}")
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
def delete(self, row_id: int) -> bool:
|
|
84
|
+
try:
|
|
85
|
+
self.cursor.execute(f"DELETE FROM {self.table_name} WHERE {self._primary_key}=?", (row_id,))
|
|
86
|
+
self.conn.commit()
|
|
87
|
+
return True
|
|
88
|
+
except Exception:
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
def delete_table(self, table_name: str = None):
|
|
92
|
+
tname = table_name or self.table_name
|
|
93
|
+
self.cursor.execute(f"DROP TABLE IF EXISTS {tname}")
|
|
94
|
+
self.conn.commit()
|
|
95
|
+
|
|
96
|
+
def db_deeep_interface(self) -> Dict[str, List[Dict]]:
|
|
97
|
+
result = {}
|
|
98
|
+
for table in self.available_tables:
|
|
99
|
+
rows = self.cursor.execute(f"SELECT * FROM {table}").fetchall()
|
|
100
|
+
result[table] = [dict(row) for row in rows]
|
|
101
|
+
return result
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
class TableBase:
|
|
4
|
+
@property
|
|
5
|
+
def table_name(self) -> str:
|
|
6
|
+
return self.__class__.__name__.lower()
|
|
7
|
+
|
|
8
|
+
def table_fields(self) -> List[str]:
|
|
9
|
+
fields = []
|
|
10
|
+
for name, value in self.__class__.__dict__.items():
|
|
11
|
+
if name.startswith('__') and name.endswith('__'):
|
|
12
|
+
continue
|
|
13
|
+
if name.startswith('_'):
|
|
14
|
+
continue
|
|
15
|
+
if callable(value):
|
|
16
|
+
continue
|
|
17
|
+
fields.append(name)
|
|
18
|
+
return fields
|
|
19
|
+
|
|
20
|
+
def _column_type(self, field_name: str) -> str:
|
|
21
|
+
value = getattr(self.__class__, field_name, None)
|
|
22
|
+
if isinstance(value, int):
|
|
23
|
+
return "INTEGER"
|
|
24
|
+
elif isinstance(value, float):
|
|
25
|
+
return "REAL"
|
|
26
|
+
elif isinstance(value, str):
|
|
27
|
+
return "TEXT"
|
|
28
|
+
else:
|
|
29
|
+
return "TEXT"
|
|
30
|
+
|
|
31
|
+
def _create_table_sql(self, primary_key: str = None) -> str:
|
|
32
|
+
fields = self.table_fields()
|
|
33
|
+
if not fields:
|
|
34
|
+
raise ValueError(f"No fields for table {self.table_name}")
|
|
35
|
+
cols = [f"{f} {self._column_type(f)}" for f in fields]
|
|
36
|
+
if primary_key and primary_key in fields:
|
|
37
|
+
cols.append(f"PRIMARY KEY ({primary_key})")
|
|
38
|
+
return f"CREATE TABLE {self.table_name} ({', '.join(cols)})"
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: af_db_teach
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Core SQLite ORM with separate educational modules
|
|
5
|
+
Home-page: https://github.com/abbasfaramarzi/af_db_teach
|
|
6
|
+
Author: Abbas Faramarzi Filabadi
|
|
7
|
+
Author-email: Abbas Faramarzi Filabadi <abbasfaramarzi@068gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
Project-URL: Homepage, https://github.com/abbasfaramarzi/af_db_teach
|
|
10
|
+
Project-URL: Bug Reports, https://github.com/abbasfaramarzi/af_db_teach/issues
|
|
11
|
+
Project-URL: Source, https://github.com/abbasfaramarzi/af_db_teach
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
# af_db_teach
|
|
25
|
+
|
|
26
|
+
A simple, educational ORM for SQLite in Python.
|
|
27
|
+
This package allows you to work with an SQLite database without writing raw SQL queries.
|
|
28
|
+
Designed for small projects and learning ORM concepts.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- Define models using Python classes and simple attributes
|
|
33
|
+
- Automatic CRUD operations (Create, Read, Update, Delete)
|
|
34
|
+
- Automatic table management (create, update schema, drop)
|
|
35
|
+
- Support for default data (`_default_data`)
|
|
36
|
+
- Helper methods like search, borrow/return (in the library example)
|
|
37
|
+
- Export all tables and data as a dictionary with `db_deeep_interface`
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install af_db_teach
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> **Note:** This package will be published on PyPI soon. You can also use it directly from the GitHub repository.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
### 1. Define a Model
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from af_db_teach import Model
|
|
53
|
+
|
|
54
|
+
class Product(Model):
|
|
55
|
+
_primary_key = "id"
|
|
56
|
+
id = 0
|
|
57
|
+
name = ""
|
|
58
|
+
price = 0.0
|
|
59
|
+
in_stock = 1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- The table name is automatically derived from the class name (lowercase): `product`
|
|
63
|
+
- Fields are defined as class attributes.
|
|
64
|
+
- Data types (INTEGER, REAL, TEXT) are inferred from the example values (`int`, `float`, `str`).
|
|
65
|
+
|
|
66
|
+
### 2. Work with the Database
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Connect and create the table
|
|
70
|
+
db = Product("shop.db")
|
|
71
|
+
|
|
72
|
+
# Insert a row
|
|
73
|
+
new_id = db.insert_one(name="Python Book", price=25000, in_stock=1)
|
|
74
|
+
|
|
75
|
+
# Get all records
|
|
76
|
+
all_products = db.get_all()
|
|
77
|
+
|
|
78
|
+
# Get a single record by primary key
|
|
79
|
+
product = db.get_one(1)
|
|
80
|
+
|
|
81
|
+
# Update a record
|
|
82
|
+
db.update(1, price=27000)
|
|
83
|
+
|
|
84
|
+
# Delete a record
|
|
85
|
+
db.delete(1)
|
|
86
|
+
|
|
87
|
+
# Drop the entire table
|
|
88
|
+
db.delete_table()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Default Data
|
|
92
|
+
|
|
93
|
+
You can define `_default_data` in your model class to insert initial records:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
class Category(Model):
|
|
97
|
+
id = 0
|
|
98
|
+
title = ""
|
|
99
|
+
|
|
100
|
+
_default_data = [
|
|
101
|
+
(1, "Electronics"),
|
|
102
|
+
(2, "Books"),
|
|
103
|
+
(3, "Clothing"),
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> Note: The order of values must match the order of fields returned by `table_fields()`.
|
|
108
|
+
|
|
109
|
+
## Model Methods
|
|
110
|
+
|
|
111
|
+
| Method | Description |
|
|
112
|
+
|--------|-------------|
|
|
113
|
+
| `insert_one(**kwargs)` | Insert a new row. Returns `lastrowid`. |
|
|
114
|
+
| `get_all(where="", params=())` | Get all rows (optional WHERE clause). |
|
|
115
|
+
| `get_one(row_id)` | Get a single row by primary key. |
|
|
116
|
+
| `update(row_id, **kwargs)` | Update specified fields. |
|
|
117
|
+
| `delete(row_id)` | Delete a row by primary key. |
|
|
118
|
+
| `delete_table(table_name=None)` | Drop the entire table. |
|
|
119
|
+
| `db_deeep_interface()` | Return a dictionary of all tables and their contents. |
|
|
120
|
+
|
|
121
|
+
## Complete Example: Library Management
|
|
122
|
+
|
|
123
|
+
The file `library_orm_demo.py` provides a practical library system example:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from af_db_teach import Model
|
|
127
|
+
from datetime import date
|
|
128
|
+
|
|
129
|
+
class Book(Model):
|
|
130
|
+
_primary_key = "id"
|
|
131
|
+
id = 0
|
|
132
|
+
title = ""
|
|
133
|
+
author = ""
|
|
134
|
+
year = 2000
|
|
135
|
+
is_available = 1
|
|
136
|
+
|
|
137
|
+
def borrow(self, book_id):
|
|
138
|
+
book = self.get_one(book_id)
|
|
139
|
+
if book and book['is_available'] == 1:
|
|
140
|
+
return self.update(book_id, is_available=0)
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
def return_book(self, book_id):
|
|
144
|
+
book = self.get_one(book_id)
|
|
145
|
+
if book and book['is_available'] == 0:
|
|
146
|
+
return self.update(book_id, is_available=1)
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
# Usage
|
|
150
|
+
book_db = Book("library.db")
|
|
151
|
+
book_db.insert_one(title="Thus Spoke Zarathustra", author="Nietzsche", year=1885)
|
|
152
|
+
book_db.borrow(1) # borrow the book
|
|
153
|
+
book_db.return_book(1) # return it
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Run the full demo:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
python library_orm_demo.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Advanced Notes
|
|
163
|
+
|
|
164
|
+
### 1. Ignoring a Table
|
|
165
|
+
|
|
166
|
+
The `Keywords` class contains a list `ignores_table_name_list`. If a table name is in this list, `create_table` will not create it. You can extend this list:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from af_db_teach import Keywords
|
|
170
|
+
Keywords.ignores_table_name_list.append("my_temp_table")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 2. Base Class `TableBase`
|
|
174
|
+
|
|
175
|
+
If you need a model without direct database connection (just the table structure), you can inherit from `TableBase`.
|
|
176
|
+
|
|
177
|
+
### 3. Connecting to an Existing Database
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
db = Model("my_database.db")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
If the database file does not exist, it will be created.
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
This project is released under the MIT License.
|
|
188
|
+
|
|
189
|
+
## Author
|
|
190
|
+
|
|
191
|
+
Abbas Faramarzi
|
|
192
|
+
[Email](mailto:abbasfaramarzi@068gmail.com)
|
|
193
|
+
[GitHub Repository](https://github.com/abbasfaramarzi/af_db_teach)
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
**af_db_teach** – A simple tool for learning and using ORM in small Python projects.
|
|
198
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
af_db_teach/__init__.py
|
|
7
|
+
af_db_teach/keywords.py
|
|
8
|
+
af_db_teach/model.py
|
|
9
|
+
af_db_teach/table_base.py
|
|
10
|
+
af_db_teach.egg-info/PKG-INFO
|
|
11
|
+
af_db_teach.egg-info/SOURCES.txt
|
|
12
|
+
af_db_teach.egg-info/dependency_links.txt
|
|
13
|
+
af_db_teach.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
af_db_teach
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "af_db_teach"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Abbas Faramarzi Filabadi", email = "abbasfaramarzi@068gmail.com"},
|
|
10
|
+
]
|
|
11
|
+
description = "Core SQLite ORM with separate educational modules"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.6"
|
|
14
|
+
license = {text = "MIT License"}
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
"Homepage" = "https://github.com/abbasfaramarzi/af_db_teach"
|
|
23
|
+
"Bug Reports" = "https://github.com/abbasfaramarzi/af_db_teach/issues"
|
|
24
|
+
"Source" = "https://github.com/abbasfaramarzi/af_db_teach"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="af_db_teach",
|
|
5
|
+
version="0.1.0",
|
|
6
|
+
author="Abbas Faramarzi Filabadi",
|
|
7
|
+
author_email="abbasfaramarzi@068gmail.com",
|
|
8
|
+
description="Core SQLite ORM with separate educational modules",
|
|
9
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
10
|
+
long_description_content_type="text/markdown",
|
|
11
|
+
url="https://github.com/abbasfaramarzi/af_db_teach",
|
|
12
|
+
packages=find_packages(),
|
|
13
|
+
classifiers=[
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
],
|
|
18
|
+
python_requires=">=3.6",
|
|
19
|
+
)
|