The create:entity command generates a new database entity class and its corresponding repository with an interactive property builder.
Usage
framefox create:entity [name]
Arguments
The name of the entity in snake_case. If not provided, you’ll be prompted to enter it.
Interactive Process
The command guides you through creating an entity step-by-step:
Entity Name - Specify the entity name (e.g., user, product)
Properties - Add properties one by one with types and constraints
Relations - Define relationships to other entities
Repository - Automatically creates the repository class
Example Session
$ framefox create:entity
What is the name of the Entity ? ( snake_case )
Entity name: user
Creating the entity 'user'
Entity 'user' and repository created successfully.
# Add properties interactively
Property name (or press Enter to finish ): username
Property type:
1. string
2. integer
3. boolean
4. datetime
5. text
6. float
7. relation
Choice: 1
Max length [255]: 100
Is unique? [y/N]: y
Is nullable? [y/N]: n
Property 'username' added successfully.
Property name (or press Enter to finish ): email
Property type: 1
Max length [255]: 255
Is unique? [y/N]: y
Is nullable? [y/N]: n
Property 'email' added successfully.
Property name (or press Enter to finish ): [Enter]
✓ Entity updated successfully
Property Types
Supported property types:
Type Python Type Database Type Options string str VARCHAR max_length, unique, nullable integer int INTEGER unique, nullable boolean bool BOOLEAN nullable, default datetime datetime DATETIME nullable, auto_now text str TEXT nullable float float FLOAT nullable relation Relationship FOREIGN KEY type, target, cascade
Generated Files
Entity File
Creates src/entity/{name}.py:
from datetime import datetime
from sqlalchemy import Boolean, Column, DateTime, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class User ( Base ):
__tablename__ = "user"
id = Column(Integer, primary_key = True , autoincrement = True )
username = Column(String( 100 ), unique = True , nullable = False )
email = Column(String( 255 ), unique = True , nullable = False )
is_active = Column(Boolean, default = True , nullable = False )
created_at = Column(DateTime, default = datetime.utcnow, nullable = False )
updated_at = Column(DateTime, default = datetime.utcnow, onupdate = datetime.utcnow)
def __repr__ ( self ):
return f "<User(id= { self .id } , username=' { self .username } ')>"
def to_dict ( self ):
return {
"id" : self .id,
"username" : self .username,
"email" : self .email,
"is_active" : self .is_active,
"created_at" : self .created_at.isoformat() if self .created_at else None ,
"updated_at" : self .updated_at.isoformat() if self .updated_at else None ,
}
Repository File
Creates src/repository/{name}_repository.py:
from typing import List, Optional
from framefox.core.orm.repository.abstract_repository import AbstractRepository
from src.entity.user import User
class UserRepository (AbstractRepository[User]):
def __init__ ( self ):
super (). __init__ (User)
def find_by_username ( self , username : str ) -> Optional[User]:
"""Find a user by username"""
return self .find_one_by({ "username" : username})
def find_by_email ( self , email : str ) -> Optional[User]:
"""Find a user by email"""
return self .find_one_by({ "email" : email})
def find_active_users ( self ) -> List[User]:
"""Find all active users"""
return self .find_by({ "is_active" : True })
Adding Properties
String Properties
Property name: name
Property type: 1 (string)
Max length [255]: 100
Is unique? [y/N]: n
Is nullable? [y/N]: n
Generates:
name = Column(String( 100 ), nullable = False )
Integer Properties
Property name: age
Property type: 2 (integer)
Is unique? [y/N]: n
Is nullable? [y/N]: y
Generates:
age = Column(Integer, nullable = True )
Boolean Properties
Property name: is_active
Property type: 3 (boolean)
Default value [True/False]: True
Is nullable? [y/N]: n
Generates:
is_active = Column(Boolean, default = True , nullable = False )
DateTime Properties
Property name: created_at
Property type: 4 (datetime)
Auto-set to now? [y/N]: y
Is nullable? [y/N]: n
Generates:
created_at = Column(DateTime, default = datetime.utcnow, nullable = False )
Text Properties
Property name: description
Property type: 5 (text)
Is nullable? [y/N]: y
Generates:
description = Column(Text, nullable = True )
Float Properties
Property name: price
Property type: 6 (float)
Is nullable? [y/N]: n
Generates:
price = Column(Float, nullable = False )
Relations
One-to-Many
Property name: posts
Property type: 7 (relation)
Relation type:
1. one-to-many
2. many-to-one
3. many-to-many
Choice: 1
Target entity: post
Generates:
from sqlalchemy.orm import relationship
posts = relationship( "Post" , back_populates = "user" )
Many-to-One
Property name: user
Property type: 7 (relation)
Relation type: 2 (many-to-one)
Target entity: user
Generates:
user_id = Column(Integer, ForeignKey( "user.id" ))
user = relationship( "User" , back_populates = "posts" )
Many-to-Many
Property name: tags
Property type: 7 (relation)
Relation type: 3 (many-to-many)
Target entity: tag
Generates association table and relationship.
Updating Existing Entities
If an entity already exists, you can add more properties:
$ framefox create:entity user
The entity 'user' already exists. You are updating it !
Property name (or press Enter to finish ): bio
# ... continue adding properties
After Creation
1. Create Migration
framefox database:create-migration
2. Apply Migration
framefox database:upgrade
3. Verify in Code
from src.entity.user import User
from src.repository.user_repository import UserRepository
# Use in your controller or service
user_repo = UserRepository()
user = user_repo.find_by_username( "john" )
Validation
The command validates:
Name Format - Must be snake_case
Property Names - Valid Python identifiers
Property Types - From supported list
Relations - Target entities must exist
Best Practices
Always include created_at and updated_at timestamps
Use is_active for soft deletes instead of actually deleting records
Make email fields unique for user entities
Use Text type for long content (descriptions, bio, etc.)
Use snake_case for both entity and property names
Add indexes for frequently queried fields
Common Patterns
User Entity
id , username (unique), email (unique), password_hash,
is_active, created_at, updated_at
Product Entity
id , name, description (text), price ( float ), stock (integer),
is_available, created_at, updated_at
Post Entity
id , title, content (text), author_id (relation to user),
published_at (datetime), is_published, created_at, updated_at
Troubleshooting
Entity Not Found in Repository
Ensure the entity is imported correctly:
from src.entity.user import User
Migration Not Detecting Changes
Verify the entity is imported in your configuration:
# migrations/env.py
from src.entity import * # Import all entities
Circular Import Errors
Use forward references for relations:
user: "User" = relationship( "User" , back_populates = "posts" )
Next Steps
Create Migration Generate migration files
Create CRUD Generate CRUD controller