Truques e Dicas¶
Esta parte é dedicada à organização de código dentro da aplicação.
Os exemplos estão mais focados no Esmerald já que o autor é o mesmo, mas novamente, pode fazer o mesmo na sua framework preferida.
Colocar a sua conecção num local centralizado¶
Provavelmente isto é o que gostaria de fazer na sua aplicação, uma vez que não quer declarar repetidamente as mesmas variáveis.
A principal razão para isto é o facto de que cada vez que se declara um registo, na verdade está a criar um novo objeto e isso não é ideal se precisar de aceder aos documentos utilizados no registo principal, certo?
Colocar os detalhes da conecçâo dentro de um ficheiro de configurações global¶
Esta é provavelmente a forma mais fácil de colocar os detalhes da conecção, especialmente para o Esmerald, já que possui uma maneira simples e fácil de acessar as configurações em qualquer parte do código.
Algo simples como isto:
"""
Generated by 'esmerald createproject'
"""
from functools import cached_property
from typing import Optional
from esmerald.conf.enums import EnvironmentType
from esmerald.conf.global_settings import EsmeraldAPISettings
from mongoz import Registry
class AppSettings(EsmeraldAPISettings):
app_name: str = "My application in production mode."
environment: Optional[str] = EnvironmentType.PRODUCTION
secret_key: str = "esmerald-insecure-h35r*b9$+hw-x2hnt5c)vva=!zn$*a7#" # auto generated
@cached_property
def db_connection(self) -> Registry:
"""
To make sure the registry and the database connection remains the same
all the time, always use the cached_property.
"""
database = "mongodb://root:mongoadmin@localhost:27017"
return Registry(database=database)
Como pode ver, agora tem a db_connection
num único local e de fácil acesso em qualquer parte do
seu código. No caso do Esmerald:
from esmerald.conf import settings
registry = settings.db_connection
Mas isso é suficiente? Não.
Como mencionado anteriormente, ao atribuir ou criar uma variável, o próprio Python gera um novo objeto com um id
diferente,
que pode ser diferente a cada vez que precisa importar as configurações nos locais necessários.
Não vamos falar sobre este truque, visto que há muita documentação online e mais adequada para este mesmo propósito.
Como resolvemos este problema? Entra em cena o lru_cache.
A LRU cache¶
LRU extends significa least recently used.
Uma técnica muito comum que visa ajudar a fazer cache de certas partes de funcionalidade dentro do código e garantir que não cria objetos extras, e é exatamente isso que precisamos.
Usando o exemplo acima, vamos agora criar um novo ficheiro chamado utils.py
, onde aplicaremos a técnica lru_cache
para a nossa db_connection
.
from functools import lru_cache
from esmerald.conf import settings
@lru_cache()
def get_db_connection():
registry = settings.db_connection
return registry
Isto garantirá que a partir de agora irá usar sempre a mesma conecção e registro dentro da aplicação, importando o get_db_connection()
sempre que for necessário.
Exemplo prático¶
Para este exemplo, teremos a seguinte estrutura (não iremos usar todos os ficheiros). Não iremos criar views visto que este não é o propósito do exemplo.
.
└── myproject
├── __init__.py
├── apps
│ ├── __init__.py
│ └── accounts
│ ├── __init__.py
│ ├── tests.py
│ └── v1
│ ├── __init__.py
│ ├── schemas.py
│ ├── urls.py
│ └── views.py
├── configs
│ ├── __init__.py
│ ├── development
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── settings.py
│ └── testing
│ ├── __init__.py
│ └── settings.py
├── main.py
├── serve.py
├── utils.py
├── tests
│ ├── __init__.py
│ └── test_app.py
└── urls.py
As configurações¶
Como mencionado anteriormente, teremos um ficheiro de configurações com as propriedades de ligação à base de dados montadas.
"""
Generated by 'esmerald createproject'
"""
from functools import cached_property
from typing import Optional
from esmerald.conf.enums import EnvironmentType
from esmerald.conf.global_settings import EsmeraldAPISettings
from mongoz import Registry
class AppSettings(EsmeraldAPISettings):
app_name: str = "My application in production mode."
environment: Optional[str] = EnvironmentType.PRODUCTION
secret_key: str = "esmerald-insecure-h35r*b9$+hw-x2hnt5c)vva=!zn$*a7#" # auto generated
@cached_property
def db_connection(self) -> Registry:
"""
To make sure the registry and the database connection remains the same
all the time, always use the cached_property.
"""
database = "mongodb://root:mongoadmin@localhost:27017"
return Registry(database=database)
Os utilitários¶
Agora criamos o utils.py
onde aplicamos a técnica LRU.
from functools import lru_cache
from esmerald.conf import settings
@lru_cache()
def get_db_connection():
registry = settings.db_connection
return registry
Os documentos¶
Agora podemos começar a criar os nossos documentos e garantir que os mantemos sempre no mesmo registo.
from datetime import datetime
from my_project.utils import get_db_connection
import mongoz
registry = get_db_connection()
class BaseDocument(mongoz.Document):
class Meta:
abstract = True
registry = registry
database = "my_db"
class User(BaseDocument):
"""
Base document for a user
"""
first_name: str = mongoz.String(max_length=150)
last_name: str = mongoz.String(max_length=150)
username: str = mongoz.String(max_length=150, unique=True)
email: str = mongoz.Email(max_length=120, unique=True)
password: str = mongoz.String(max_length=128)
last_login: datetime = mongoz.DateTime(null=True)
is_active: bool = mongoz.Boolean(default=True)
is_staff: bool = mongoz.Boolean(default=False)
is_superuser: bool = mongoz.Boolean(default=False)
Aqui aplicamos a herança para torná-lo mais limpo e legível caso queiramos ainda mais documentos.
Como também pode notar, estamos a importar o get_db_connection()
previamente criado. Agora é
o que usaremos em todos os lugares.
Notas¶
O exemplo acima mostra como pode aproveitar local centralizado para gerir suas conecções e usá-las em toda a aplicação, mantendo o código sempre limpo, não redundante e bonito.
Este exemplo pode ser aplicado a qualquer uma das frameworks preferidas e pode usar tantas técnicas diferentes quanto achar adequado para o seu propósito.
Mongoz é independente de qualquer framework.