Interactive Shell (Tinker)
Fastman's tinker command provides an interactive Python shell with your application context pre-loaded. Inspired by Laravel's Tinker, it's perfect for quick debugging, data exploration, and testing.
Basic Usageโ
fastman tinker
This starts an interactive Python shell with:
- Database session (
db) - Application settings (
settings) - SQLAlchemy
Basemodel - All your models auto-imported
Featuresโ
Pre-loaded Database Sessionโ
>>> from app.features.user.models import User
>>> users = db.query(User).all()
>>> len(users)
42
IPython Supportโ
If IPython is installed, tinker uses it automatically for:
- Syntax highlighting
- Tab completion
- Better tracebacks
- Magic commands (
%history,%timeit, etc.)
pip install ipython
fastman tinker
Tinker Tricksโ
1. Quick Data Inspectionโ
# Count records
>>> db.query(User).count()
150
# Get first/last
>>> db.query(User).first()
<User id=1 email='admin@example.com'>
>>> db.query(User).order_by(User.id.desc()).first()
<User id=150 email='latest@example.com'>
# Filter with conditions
>>> db.query(User).filter(User.is_active == True).count()
142
2. Create Test Data Quicklyโ
>>> from app.features.user.models import User
>>> user = User(email="test@example.com", name="Test User")
>>> db.add(user)
>>> db.commit()
>>> user.id
151
3. Update Recordsโ
>>> user = db.query(User).filter(User.email == "test@example.com").first()
>>> user.name = "Updated Name"
>>> db.commit()
4. Delete Recordsโ
>>> user = db.query(User).filter(User.id == 151).first()
>>> db.delete(user)
>>> db.commit()
5. Raw SQL Queriesโ
>>> from sqlalchemy import text
>>> result = db.execute(text("SELECT COUNT(*) FROM users"))
>>> result.scalar()
150
6. Explore Relationshipsโ
>>> user = db.query(User).first()
>>> user.posts # Lazy load related posts
[<Post id=1>, <Post id=2>, <Post id=3>]
>>> user.orders[-1].total # Latest order total
Decimal('99.99')
7. Test Servicesโ
>>> from app.features.user.service import UserService
>>> service = UserService(db)
>>> service.get_active_users()
[<User id=1>, <User id=2>, ...]
8. Inspect Model Schemaโ
>>> User.__table__.columns.keys()
['id', 'email', 'name', 'password', 'is_active', 'created_at']
>>> for col in User.__table__.columns:
... print(f"{col.name}: {col.type}")
id: INTEGER
email: VARCHAR(255)
name: VARCHAR(100)
...
9. Check Environmentโ
>>> settings.DATABASE_URL
'postgresql://localhost/myapp'
>>> settings.DEBUG
True
>>> settings.SECRET_KEY[:10]
'abc123...'
10. Bulk Operationsโ
# Bulk insert
>>> users = [User(email=f"user{i}@test.com") for i in range(100)]
>>> db.add_all(users)
>>> db.commit()
# Bulk update
>>> db.query(User).filter(User.is_active == False).update({"is_active": True})
>>> db.commit()
# Bulk delete
>>> db.query(User).filter(User.email.like("%@test.com")).delete()
>>> db.commit()
IPython Magic Commandsโ
When using IPython, these magic commands are helpful:
| Command | Description |
|---|---|
%history | Show command history |
%timeit | Time execution of a statement |
%who | List all variables |
%whos | Detailed variable list |
%reset | Clear all variables |
%paste | Paste from clipboard |
%edit | Open editor for multi-line code |
Example: Timing Queriesโ
>>> %timeit db.query(User).filter(User.is_active == True).all()
2.34 ms ยฑ 123 ยตs per loop
Tipsโ
Use Rollback for Safety
When experimenting with data changes, wrap operations in a transaction you can rollback:
>>> user.name = "Oops"
>>> db.rollback() # Undo changes
Exit Cleanly
Always use exit() or Ctrl+D to exit tinker, which properly closes the database connection.
Production Caution
Be careful running tinker in production! Any database changes are permanent. Consider using a read-only database connection for production debugging.