Spaces:
Paused
Paused
File size: 6,132 Bytes
50c09c8 b683f7b 50c09c8 8072ab3 50c09c8 b683f7b 50c09c8 b683f7b 50c09c8 b683f7b 50c09c8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | """
Modelos Pydantic usados para validar entrada e formatar saída da API.
"""
import json
from datetime import datetime
from enum import Enum
from typing import Optional
from pydantic import BaseModel, Field, field_validator
class TipoNegocio(str, Enum):
venda = "Venda"
locacao = "Locação"
class TipoImovel(str, Enum):
casa = "Casa"
apartamento = "Apartamento"
terreno = "Terreno"
comercial = "Comercial"
sala_comercial = "Sala Comercial"
galpao = "Galpão"
chacara_sitio = "Chácara/Sítio"
cobertura = "Cobertura"
kitnet = "Kitnet/Studio"
class StatusAnuncio(str, Enum):
disponivel = "Disponível"
lancamento = "Lançamento"
vendido = "Vendido"
alugado = "Alugado"
reservado = "Reservado"
inativo = "Inativo"
class AnuncioBase(BaseModel):
tipo_negocio: TipoNegocio
tipo_imovel: TipoImovel
titulo: str = Field(..., min_length=3, max_length=150)
descricao: str = Field("", max_length=3000)
endereco: str = Field("", max_length=200)
bairro: str = Field("", max_length=100)
cidade: str = Field(..., min_length=2, max_length=100)
estado: str = Field(..., min_length=2, max_length=2, description="Sigla da UF, ex: PR")
cep: str = Field("", max_length=10)
preco: float = Field(..., ge=0)
condominio: Optional[float] = Field(0, ge=0)
iptu: Optional[float] = Field(0, ge=0)
area_util: Optional[float] = Field(0, ge=0)
area_total: Optional[float] = Field(0, ge=0)
quartos: Optional[int] = Field(0, ge=0)
suites: Optional[int] = Field(0, ge=0)
banheiros: Optional[int] = Field(0, ge=0)
vagas_garagem: Optional[int] = Field(0, ge=0)
status: StatusAnuncio = StatusAnuncio.disponivel
destaque: Optional[bool] = False
corretor_responsavel: str = Field("", max_length=100)
telefone_contato: str = Field("", max_length=30)
midias: Optional[str] = Field(
"[]",
description="JSON com a lista de URLs completas de imagens/vídeos, ex: [\"https://.../foto1.jpg\"]",
)
@field_validator("estado")
@classmethod
def uf_maiuscula(cls, v: str) -> str:
return v.upper()
@field_validator("midias", mode="before")
@classmethod
def midias_json_valido(cls, v) -> str:
"""Aceita string JSON de lista de URLs, lista Python direta, ou vazio -> normaliza sempre para JSON string."""
if v in (None, ""):
return "[]"
if isinstance(v, list):
return json.dumps([str(u) for u in v if u])
try:
parsed = json.loads(v)
except (json.JSONDecodeError, TypeError):
raise ValueError("midias deve ser uma lista JSON válida de URLs, ex: [\"https://.../foto1.jpg\"]")
if not isinstance(parsed, list):
raise ValueError("midias deve ser uma lista JSON de URLs")
return json.dumps([str(u) for u in parsed if u])
class AnuncioCreate(AnuncioBase):
pass
class AnuncioUpdate(BaseModel):
"""Todos os campos opcionais - usado no PATCH (atualização parcial)."""
tipo_negocio: Optional[TipoNegocio] = None
tipo_imovel: Optional[TipoImovel] = None
titulo: Optional[str] = Field(None, min_length=3, max_length=150)
descricao: Optional[str] = None
endereco: Optional[str] = None
bairro: Optional[str] = None
cidade: Optional[str] = None
estado: Optional[str] = Field(None, min_length=2, max_length=2)
cep: Optional[str] = None
preco: Optional[float] = Field(None, ge=0)
condominio: Optional[float] = Field(None, ge=0)
iptu: Optional[float] = Field(None, ge=0)
area_util: Optional[float] = Field(None, ge=0)
area_total: Optional[float] = Field(None, ge=0)
quartos: Optional[int] = Field(None, ge=0)
suites: Optional[int] = Field(None, ge=0)
banheiros: Optional[int] = Field(None, ge=0)
vagas_garagem: Optional[int] = Field(None, ge=0)
status: Optional[StatusAnuncio] = None
destaque: Optional[bool] = None
corretor_responsavel: Optional[str] = None
telefone_contato: Optional[str] = None
midias: Optional[str] = None
@field_validator("midias", mode="before")
@classmethod
def midias_json_valido(cls, v):
if v in (None, ""):
return v
if isinstance(v, list):
return json.dumps([str(u) for u in v if u])
try:
parsed = json.loads(v)
except (json.JSONDecodeError, TypeError):
raise ValueError("midias deve ser uma lista JSON válida de URLs")
if not isinstance(parsed, list):
raise ValueError("midias deve ser uma lista JSON de URLs")
return json.dumps([str(u) for u in parsed if u])
class AnuncioResponse(AnuncioBase):
id: int
data_cadastro: datetime
data_atualizacao: datetime
class OrdenacaoAnuncio(str, Enum):
mais_recentes = "mais_recentes"
mais_antigos = "mais_antigos"
preco_asc = "preco_asc"
preco_desc = "preco_desc"
area_asc = "area_asc"
area_desc = "area_desc"
class FacetaItem(BaseModel):
valor: str
quantidade: int
class FaixaValores(BaseModel):
min: float
max: float
class OpcoesFiltroResponse(BaseModel):
total_anuncios: int
tipos_negocio: list[FacetaItem]
tipos_imovel: list[FacetaItem]
status: list[FacetaItem]
cidades: list[FacetaItem]
bairros: list[FacetaItem]
faixa_preco: FaixaValores
faixa_area: FaixaValores
quartos_disponiveis: list[int]
vagas_disponiveis: list[int]
class FacetasBusca(BaseModel):
tipos_imovel: list[FacetaItem]
cidades: list[FacetaItem]
bairros: list[FacetaItem]
status: list[FacetaItem]
faixa_preco: FaixaValores
faixa_area: FaixaValores
class BuscaExploratoriaResponse(BaseModel):
total: int
skip: int
limit: int
ordenar_por: OrdenacaoAnuncio
resultados: list[AnuncioResponse]
facetas: FacetasBusca
class ResumoStats(BaseModel):
total_anuncios: int
total_venda: int
total_locacao: int
total_disponiveis: int
preco_medio_venda: float
preco_medio_locacao: float
por_tipo_imovel: dict
por_cidade: dict
|