data driven about us screen
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,79 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.auth import get_current_admin_user
|
||||
from app.database import get_session
|
||||
from app.models import CommunityHighlight
|
||||
from app.schemas import CommunityHighlightCreate, CommunityHighlightUpdate, CommunityHighlightResponse
|
||||
from app.user_models import User
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=list[CommunityHighlightResponse])
|
||||
async def list_community_highlights(
|
||||
active: Optional[bool] = Query(None, description="Filter by active status"),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
query = select(CommunityHighlight).order_by(CommunityHighlight.display_order)
|
||||
if active is not None:
|
||||
query = query.where(CommunityHighlight.active == active)
|
||||
result = await session.execute(query)
|
||||
return list(result.scalars().all())
|
||||
|
||||
|
||||
@router.get("/{highlight_id}", response_model=CommunityHighlightResponse)
|
||||
async def get_community_highlight(highlight_id: int, session: AsyncSession = Depends(get_session)):
|
||||
result = await session.execute(select(CommunityHighlight).where(CommunityHighlight.id == highlight_id))
|
||||
highlight = result.scalar_one_or_none()
|
||||
if not highlight:
|
||||
return {"error": "Community highlight not found"}
|
||||
return highlight
|
||||
|
||||
|
||||
@router.post("/", response_model=CommunityHighlightResponse, status_code=201)
|
||||
async def create_community_highlight(
|
||||
payload: CommunityHighlightCreate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
highlight = CommunityHighlight(**payload.model_dump(), active=True)
|
||||
session.add(highlight)
|
||||
await session.commit()
|
||||
await session.refresh(highlight)
|
||||
return highlight
|
||||
|
||||
|
||||
@router.put("/{highlight_id}", response_model=CommunityHighlightResponse)
|
||||
async def update_community_highlight(
|
||||
highlight_id: int,
|
||||
payload: CommunityHighlightUpdate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
result = await session.execute(select(CommunityHighlight).where(CommunityHighlight.id == highlight_id))
|
||||
highlight = result.scalar_one_or_none()
|
||||
if not highlight:
|
||||
return {"error": "Community highlight not found"}
|
||||
for key, value in payload.model_dump(exclude_unset=True).items():
|
||||
setattr(highlight, key, value)
|
||||
await session.commit()
|
||||
await session.refresh(highlight)
|
||||
return highlight
|
||||
|
||||
|
||||
@router.delete("/{highlight_id}", status_code=204)
|
||||
async def delete_community_highlight(
|
||||
highlight_id: int,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
result = await session.execute(select(CommunityHighlight).where(CommunityHighlight.id == highlight_id))
|
||||
highlight = result.scalar_one_or_none()
|
||||
if not highlight:
|
||||
return {"error": "Community highlight not found"}
|
||||
await session.delete(highlight)
|
||||
await session.commit()
|
||||
@@ -0,0 +1,79 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.auth import get_current_admin_user
|
||||
from app.database import get_session
|
||||
from app.models import HistoryEntry
|
||||
from app.schemas import HistoryEntryCreate, HistoryEntryUpdate, HistoryEntryResponse
|
||||
from app.user_models import User
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=list[HistoryEntryResponse])
|
||||
async def list_history_entries(
|
||||
active: Optional[bool] = Query(None, description="Filter by active status"),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
query = select(HistoryEntry).order_by(HistoryEntry.display_order)
|
||||
if active is not None:
|
||||
query = query.where(HistoryEntry.active == active)
|
||||
result = await session.execute(query)
|
||||
return list(result.scalars().all())
|
||||
|
||||
|
||||
@router.get("/{entry_id}", response_model=HistoryEntryResponse)
|
||||
async def get_history_entry(entry_id: int, session: AsyncSession = Depends(get_session)):
|
||||
result = await session.execute(select(HistoryEntry).where(HistoryEntry.id == entry_id))
|
||||
entry = result.scalar_one_or_none()
|
||||
if not entry:
|
||||
return {"error": "History entry not found"}
|
||||
return entry
|
||||
|
||||
|
||||
@router.post("/", response_model=HistoryEntryResponse, status_code=201)
|
||||
async def create_history_entry(
|
||||
payload: HistoryEntryCreate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
entry = HistoryEntry(**payload.model_dump(), active=True)
|
||||
session.add(entry)
|
||||
await session.commit()
|
||||
await session.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
@router.put("/{entry_id}", response_model=HistoryEntryResponse)
|
||||
async def update_history_entry(
|
||||
entry_id: int,
|
||||
payload: HistoryEntryUpdate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
result = await session.execute(select(HistoryEntry).where(HistoryEntry.id == entry_id))
|
||||
entry = result.scalar_one_or_none()
|
||||
if not entry:
|
||||
return {"error": "History entry not found"}
|
||||
for key, value in payload.model_dump(exclude_unset=True).items():
|
||||
setattr(entry, key, value)
|
||||
await session.commit()
|
||||
await session.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
@router.delete("/{entry_id}", status_code=204)
|
||||
async def delete_history_entry(
|
||||
entry_id: int,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
result = await session.execute(select(HistoryEntry).where(HistoryEntry.id == entry_id))
|
||||
entry = result.scalar_one_or_none()
|
||||
if not entry:
|
||||
return {"error": "History entry not found"}
|
||||
await session.delete(entry)
|
||||
await session.commit()
|
||||
@@ -0,0 +1,79 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.auth import get_current_admin_user
|
||||
from app.database import get_session
|
||||
from app.models import TeamMember
|
||||
from app.schemas import TeamMemberCreate, TeamMemberUpdate, TeamMemberResponse
|
||||
from app.user_models import User
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=list[TeamMemberResponse])
|
||||
async def list_team_members(
|
||||
active: Optional[bool] = Query(None, description="Filter by active status"),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
query = select(TeamMember).order_by(TeamMember.display_order)
|
||||
if active is not None:
|
||||
query = query.where(TeamMember.active == active)
|
||||
result = await session.execute(query)
|
||||
return list(result.scalars().all())
|
||||
|
||||
|
||||
@router.get("/{member_id}", response_model=TeamMemberResponse)
|
||||
async def get_team_member(member_id: int, session: AsyncSession = Depends(get_session)):
|
||||
result = await session.execute(select(TeamMember).where(TeamMember.id == member_id))
|
||||
member = result.scalar_one_or_none()
|
||||
if not member:
|
||||
return {"error": "Team member not found"}
|
||||
return member
|
||||
|
||||
|
||||
@router.post("/", response_model=TeamMemberResponse, status_code=201)
|
||||
async def create_team_member(
|
||||
payload: TeamMemberCreate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
member = TeamMember(**payload.model_dump(), active=True)
|
||||
session.add(member)
|
||||
await session.commit()
|
||||
await session.refresh(member)
|
||||
return member
|
||||
|
||||
|
||||
@router.put("/{member_id}", response_model=TeamMemberResponse)
|
||||
async def update_team_member(
|
||||
member_id: int,
|
||||
payload: TeamMemberUpdate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
result = await session.execute(select(TeamMember).where(TeamMember.id == member_id))
|
||||
member = result.scalar_one_or_none()
|
||||
if not member:
|
||||
return {"error": "Team member not found"}
|
||||
for key, value in payload.model_dump(exclude_unset=True).items():
|
||||
setattr(member, key, value)
|
||||
await session.commit()
|
||||
await session.refresh(member)
|
||||
return member
|
||||
|
||||
|
||||
@router.delete("/{member_id}", status_code=204)
|
||||
async def delete_team_member(
|
||||
member_id: int,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
_: User = Depends(get_current_admin_user),
|
||||
):
|
||||
result = await session.execute(select(TeamMember).where(TeamMember.id == member_id))
|
||||
member = result.scalar_one_or_none()
|
||||
if not member:
|
||||
return {"error": "Team member not found"}
|
||||
await session.delete(member)
|
||||
await session.commit()
|
||||
+5
-2
@@ -8,9 +8,9 @@ from sqlalchemy import func, select
|
||||
|
||||
from app.config import settings
|
||||
from app.database import async_session, engine
|
||||
from app.models import Base, Program, StationConfig
|
||||
from app.models import Base, Program, StationConfig, HistoryEntry, TeamMember, CommunityHighlight
|
||||
from app.user_models import User
|
||||
from app.api import programs, events, tiers, auth, station_config
|
||||
from app.api import programs, events, tiers, auth, station_config, history, team, community
|
||||
|
||||
|
||||
async def _ensure_station_config(session):
|
||||
@@ -96,6 +96,9 @@ app.include_router(programs.router, prefix="/api/programs", tags=["programs"])
|
||||
app.include_router(events.router, prefix="/api/events", tags=["events"])
|
||||
app.include_router(tiers.router, prefix="/api/tiers", tags=["tiers"])
|
||||
app.include_router(station_config.router, prefix="/api/station-config", tags=["station-config"])
|
||||
app.include_router(history.router, prefix="/api/history", tags=["history"])
|
||||
app.include_router(team.router, prefix="/api/team", tags=["team"])
|
||||
app.include_router(community.router, prefix="/api/community", tags=["community"])
|
||||
|
||||
# Serve uploaded files (dev only — Nginx handles this in production)
|
||||
if settings.ENV != "production":
|
||||
|
||||
@@ -80,3 +80,37 @@ class StationConfig(Base):
|
||||
phone = Column(String(30), nullable=False, default="(970) 555-0198")
|
||||
email = Column(String(100), nullable=False, default="hello@kmountainflower.org")
|
||||
website = Column(String(200), nullable=False, default="kmountainflower.org")
|
||||
|
||||
|
||||
class HistoryEntry(Base):
|
||||
__tablename__ = "history_entries"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
year = Column(Integer, nullable=False)
|
||||
title = Column(String(200), nullable=False)
|
||||
body = Column(Text, nullable=False)
|
||||
display_order = Column(Integer, nullable=False)
|
||||
active = Column(Boolean, default=True)
|
||||
|
||||
|
||||
class TeamMember(Base):
|
||||
__tablename__ = "team_members"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
title = Column(String(150), nullable=False)
|
||||
bio = Column(Text, nullable=True)
|
||||
photo_url = Column(String(500), nullable=True)
|
||||
display_order = Column(Integer, nullable=False)
|
||||
active = Column(Boolean, default=True)
|
||||
|
||||
|
||||
class CommunityHighlight(Base):
|
||||
__tablename__ = "community_highlights"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
icon = Column(String(10), nullable=False)
|
||||
title = Column(String(200), nullable=False)
|
||||
description = Column(Text, nullable=False)
|
||||
display_order = Column(Integer, nullable=False)
|
||||
active = Column(Boolean, default=True)
|
||||
|
||||
@@ -156,3 +156,90 @@ class StationConfigUpdate(BaseModel):
|
||||
phone: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
website: Optional[str] = None
|
||||
|
||||
|
||||
# ── HistoryEntry ──────────────────────────────────────────
|
||||
|
||||
class HistoryEntryCreate(BaseModel):
|
||||
year: int
|
||||
title: str
|
||||
body: str
|
||||
display_order: int
|
||||
|
||||
|
||||
class HistoryEntryUpdate(BaseModel):
|
||||
year: Optional[int] = None
|
||||
title: Optional[str] = None
|
||||
body: Optional[str] = None
|
||||
display_order: Optional[int] = None
|
||||
active: Optional[bool] = None
|
||||
|
||||
|
||||
class HistoryEntryResponse(BaseModel):
|
||||
id: int
|
||||
year: int
|
||||
title: str
|
||||
body: str
|
||||
display_order: int
|
||||
active: bool
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ── TeamMember ─────────────────────────────────────────────
|
||||
|
||||
class TeamMemberCreate(BaseModel):
|
||||
name: str
|
||||
title: str
|
||||
bio: Optional[str] = None
|
||||
photo_url: Optional[str] = None
|
||||
display_order: int
|
||||
|
||||
|
||||
class TeamMemberUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
bio: Optional[str] = None
|
||||
photo_url: Optional[str] = None
|
||||
display_order: Optional[int] = None
|
||||
active: Optional[bool] = None
|
||||
|
||||
|
||||
class TeamMemberResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
title: str
|
||||
bio: Optional[str]
|
||||
photo_url: Optional[str]
|
||||
display_order: int
|
||||
active: bool
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ── CommunityHighlight ─────────────────────────────────────
|
||||
|
||||
class CommunityHighlightCreate(BaseModel):
|
||||
icon: str
|
||||
title: str
|
||||
description: str
|
||||
display_order: int
|
||||
|
||||
|
||||
class CommunityHighlightUpdate(BaseModel):
|
||||
icon: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
display_order: Optional[int] = None
|
||||
active: Optional[bool] = None
|
||||
|
||||
|
||||
class CommunityHighlightResponse(BaseModel):
|
||||
id: int
|
||||
icon: str
|
||||
title: str
|
||||
description: str
|
||||
display_order: int
|
||||
active: bool
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
+149
@@ -15,6 +15,7 @@ from sqlalchemy import select
|
||||
|
||||
from app.database import async_session
|
||||
from app.models import Program, Event, DonationTier, StationConfig
|
||||
from app.models import HistoryEntry, TeamMember, CommunityHighlight
|
||||
|
||||
# ── Seed data ──────────────────────────────────────────────
|
||||
|
||||
@@ -113,6 +114,91 @@ STATION_CONFIG: dict = {
|
||||
"website": "kmountainflower.org",
|
||||
}
|
||||
|
||||
HISTORY_ENTRIES: list[dict] = [
|
||||
{
|
||||
"year": 1987,
|
||||
"title": "The Idea Takes Root",
|
||||
"body": "A small group of mountain residents gathered around a kitchen table with a shared dream: a radio station owned by the community, for the community. With nothing but conviction and a stack of handwritten letters to the FCC, they began the long road toward bringing independent radio to the high country.",
|
||||
"display_order": 1,
|
||||
},
|
||||
{
|
||||
"year": 1991,
|
||||
"title": "FCC License Granted",
|
||||
"body": "After years of paperwork, public hearings, and grassroots fundraising, the Federal Communications Commission approved the construction permit. The call sign KMTN was chosen — a nod to the mountain terrain that defines the region and the people who call it home.",
|
||||
"display_order": 2,
|
||||
},
|
||||
{
|
||||
"year": 1995,
|
||||
"title": "First Broadcast",
|
||||
"body": "On a crisp September morning, KMTN signed on the air for the first time. The opening broadcast featured a live bluegrass set from the studio, followed by interviews with local farmers, teachers, and business owners. The signal reached every valley and ridge within a 40-mile radius.",
|
||||
"display_order": 3,
|
||||
},
|
||||
{
|
||||
"year": 2008,
|
||||
"title": "Studio Expansion",
|
||||
"body": "A generous community-driven capital campaign funded the construction of a new broadcast studio — doubling production space and adding a dedicated live-performance room. The expansion also brought upgraded transmission equipment, extending the station's reach to surrounding counties.",
|
||||
"display_order": 4,
|
||||
},
|
||||
]
|
||||
|
||||
TEAM_MEMBERS: list[dict] = [
|
||||
{
|
||||
"name": "Margaret Ellis",
|
||||
"title": "Board Chair",
|
||||
"bio": "Margaret has served on the KMTN board for over fifteen years. A retired schoolteacher, she believes community radio is the backbone of civic engagement.",
|
||||
"photo_url": None,
|
||||
"display_order": 1,
|
||||
},
|
||||
{
|
||||
"name": "James Whitfield",
|
||||
"title": "General Manager",
|
||||
"bio": "James joined KMTN as a volunteer DJ in 2002 and has been steering the station's operations ever since. He oversees programming, finance, and community outreach.",
|
||||
"photo_url": None,
|
||||
"display_order": 2,
|
||||
},
|
||||
{
|
||||
"name": "Dr. Priya Nair",
|
||||
"title": "Program Director",
|
||||
"bio": "Dr. Nair brings two decades of media experience to KMTN. She curates the station's diverse lineup and mentors the next generation of local broadcasters.",
|
||||
"photo_url": None,
|
||||
"display_order": 3,
|
||||
},
|
||||
{
|
||||
"name": "Carlos Mendez",
|
||||
"title": "Community Outreach Coordinator",
|
||||
"bio": "Carlos organizes station events, volunteer drives, and school partnerships. His Evening Echoes show is one of the station's most-listened-to programs.",
|
||||
"photo_url": None,
|
||||
"display_order": 4,
|
||||
},
|
||||
]
|
||||
|
||||
COMMUNITY_HIGHLIGHTS: list[dict] = [
|
||||
{
|
||||
"icon": "🎵",
|
||||
"title": "Our Music",
|
||||
"description": "From bluegrass and folk to jazz and classical, our playlists reflect the rich cultural tapestry of the high country and its neighbors. We feature local artists alongside the world's best voices.",
|
||||
"display_order": 1,
|
||||
},
|
||||
{
|
||||
"icon": "🤝",
|
||||
"title": "Our Community",
|
||||
"description": "Every show is staffed by volunteers who live and work in these mountains. From high school DJs to retired teachers, our team is your community — passionate about sharing what they love.",
|
||||
"display_order": 2,
|
||||
},
|
||||
{
|
||||
"icon": "📡",
|
||||
"title": "Our Reach",
|
||||
"description": "Over the air on 98.7 FM and streaming live worldwide. Whether you're hiking the ridgeline or on the other side of the planet, our signal — and our welcome — goes everywhere.",
|
||||
"display_order": 3,
|
||||
},
|
||||
{
|
||||
"icon": "🌱",
|
||||
"title": "Our Mission",
|
||||
"description": "To keep public radio free, independent, and deeply rooted in place. No corporate advertising, no spin — just music, conversation, and community served with care.",
|
||||
"display_order": 4,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────
|
||||
|
||||
@@ -174,6 +260,51 @@ async def _upsert_station_config(session, data: dict) -> None:
|
||||
session.add(StationConfig(**data))
|
||||
|
||||
|
||||
async def _upsert_history_entry(session, data: dict) -> None:
|
||||
"""Get-or-create a history entry matched on (year, title)."""
|
||||
existing = await session.execute(
|
||||
select(HistoryEntry).where(
|
||||
HistoryEntry.year == data["year"],
|
||||
HistoryEntry.title == data["title"],
|
||||
)
|
||||
)
|
||||
entry = existing.scalar_one_or_none()
|
||||
if entry:
|
||||
for key, value in data.items():
|
||||
setattr(entry, key, value)
|
||||
else:
|
||||
session.add(HistoryEntry(**data, active=True))
|
||||
|
||||
|
||||
async def _upsert_team_member(session, data: dict) -> None:
|
||||
"""Get-or-create a team member matched on name."""
|
||||
existing = await session.execute(
|
||||
select(TeamMember).where(TeamMember.name == data["name"])
|
||||
)
|
||||
member = existing.scalar_one_or_none()
|
||||
if member:
|
||||
for key, value in data.items():
|
||||
setattr(member, key, value)
|
||||
else:
|
||||
session.add(TeamMember(**data, active=True))
|
||||
|
||||
|
||||
async def _upsert_community_highlight(session, data: dict) -> None:
|
||||
"""Get-or-create a community highlight matched on (icon, title)."""
|
||||
existing = await session.execute(
|
||||
select(CommunityHighlight).where(
|
||||
CommunityHighlight.icon == data["icon"],
|
||||
CommunityHighlight.title == data["title"],
|
||||
)
|
||||
)
|
||||
highlight = existing.scalar_one_or_none()
|
||||
if highlight:
|
||||
for key, value in data.items():
|
||||
setattr(highlight, key, value)
|
||||
else:
|
||||
session.add(CommunityHighlight(**data, active=True))
|
||||
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────
|
||||
|
||||
async def seed() -> None:
|
||||
@@ -198,6 +329,21 @@ async def seed() -> None:
|
||||
await session.commit()
|
||||
print(" ✓ Seeded station config")
|
||||
|
||||
for data in HISTORY_ENTRIES:
|
||||
await _upsert_history_entry(session, data)
|
||||
await session.commit()
|
||||
print(f" ✓ Seeded {len(HISTORY_ENTRIES)} history entries")
|
||||
|
||||
for data in TEAM_MEMBERS:
|
||||
await _upsert_team_member(session, data)
|
||||
await session.commit()
|
||||
print(f" ✓ Seeded {len(TEAM_MEMBERS)} team members")
|
||||
|
||||
for data in COMMUNITY_HIGHLIGHTS:
|
||||
await _upsert_community_highlight(session, data)
|
||||
await session.commit()
|
||||
print(f" ✓ Seeded {len(COMMUNITY_HIGHLIGHTS)} community highlights")
|
||||
|
||||
|
||||
async def truncate_all() -> None:
|
||||
"""Remove all seed data from the database."""
|
||||
@@ -206,6 +352,9 @@ async def truncate_all() -> None:
|
||||
await session.execute(Event.__table__.delete())
|
||||
await session.execute(DonationTier.__table__.delete())
|
||||
await session.execute(StationConfig.__table__.delete())
|
||||
await session.execute(HistoryEntry.__table__.delete())
|
||||
await session.execute(TeamMember.__table__.delete())
|
||||
await session.execute(CommunityHighlight.__table__.delete())
|
||||
await session.commit()
|
||||
print(" ✓ Truncated all tables")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user