Skip to main content
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

name
string
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:
  1. Entity Name - Specify the entity name (e.g., user, product)
  2. Properties - Add properties one by one with types and constraints
  3. Relations - Define relationships to other entities
  4. 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:
TypePython TypeDatabase TypeOptions
stringstrVARCHARmax_length, unique, nullable
integerintINTEGERunique, nullable
booleanboolBOOLEANnullable, default
datetimedatetimeDATETIMEnullable, auto_now
textstrTEXTnullable
floatfloatFLOATnullable
relationRelationshipFOREIGN KEYtype, 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:
  1. Name Format - Must be snake_case
  2. Property Names - Valid Python identifiers
  3. Property Types - From supported list
  4. 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

Build docs developers (and LLMs) love