Estilo de código#
Pautas de estilo de código para contribuciones de Construbot.
Estilo pitón#
Siga PEP 8#
Formato de código:
4 espacios para sangría (sin pestañas)
Longitud máxima de línea: 100 caracteres (no estricto 79)
2 líneas en blanco entre funciones/clases de nivel superior
1 línea en blanco entre métodos
Usar negro:
black .
Usar isorción:
isort .
Convenciones de nomenclatura#
# Variables and functions: snake_case
user_count = 10
def calculate_total():
pass
# Classes: PascalCase
class ContractManager:
pass
# Constants: UPPER_CASE
MAX_CONTRACTS = 100
# Private: _leading_underscore
def _internal_helper():
pass
Consejos de tipo#
Se recomienda pero no es obligatorio:
def get_contracts(company: Company) -> QuerySet[Contrato]:
return Contrato.objects.filter(company=company)
cadenas de documentos#
Usa el estilo de Google:
def create_contract(company, folio, amount):
"""Create a new contract.
Args:
company (Company): The company for this contract
folio (str): Reference number
amount (Decimal): Contract amount
Returns:
Contrato: The created contract
Raises:
ValidationError: If folio already exists
"""
...
Estilo Django#
Modelo de mejores prácticas#
Incluye siempre compañía:
class MyModel(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
Usar nombre_detallado:
class Contrato(models.Model):
folio = models.CharField(
max_length=100,
verbose_name="Reference Number",
help_text="Unique identifier for this contract"
)
Metaopciones:
class Meta:
ordering = ['-created_at']
unique_together = ('company', 'folio')
verbose_name_plural = "Contracts"
Ver mejores prácticas#
Usar vistas basadas en clases:
from django.views.generic import ListView
class ContractListView(LoginRequiredMixin, ListView):
model = Contrato
template_name = 'contracts/list.html'
def get_queryset(self):
return Contrato.objects.filter(
company=self.request.user.active_company
)
Siempre alcance a la empresa:
# GOOD
contracts = Contrato.objects.filter(company=request.user.active_company)
# BAD
contracts = Contrato.objects.all() # Leaks data!
Optimización de consultas#
Usar select_ related:
# Avoid N+1 queries
contracts = Contrato.objects.select_related(
'contraparte',
'sitio'
)
Usar prefetch_relacionado:
users = User.objects.prefetch_related('companies')
Seguridad#
Nunca confíes en la entrada del usuario:
# Use Django forms for validation
form = ContractForm(request.POST)
if form.is_valid():
contract = form.save()
Utilice get_object_or_404:
contract = get_object_or_404(Contrato, id=contract_id)
Verificar permisos:
if not request.user.nivel_acceso.nivel >= 3:
raise PermissionDenied()
Estilo de prueba#
Borrar nombres de pruebas:
def test_contract_creation_with_valid_data():
pass
def test_contract_creation_fails_with_duplicate_folio():
pass
Utilice la configuración para datos comunes:
class ContractTestCase(TestCase):
def setUp(self):
self.company = Company.objects.create(...)
def test_something(self):
contract = Contrato.objects.create(company=self.company)
Una afirmación por prueba (idealmente):
def test_contract_folio_is_uppercase(self):
contract = Contrato.objects.create(folio="abc")
self.assertEqual(contract.folio, "ABC")
Mensajes de confirmación de Git#
Formato:
Short summary (50 chars max)
More detailed explanation if needed. Wrap at 72 characters.
- List of changes
- Another change
Buenos ejemplos:
Add hierarchical contract support
Implement django-treebeard for parent/child contract relationships.
Includes migration, model updates, and tree query methods.
Fix: Prevent data leak in contract list view
Ensure contracts are filtered by active_company before display.
Malos ejemplos:
Fixed stuff
WIP
asdf
Updated code
Patrones comunes#
Patrón de fábrica para pruebas:
class ContractFactory:
@staticmethod
def create(**kwargs):
defaults = {
'company': CompanyFactory.create(),
'folio': 'C-001',
'monto': Decimal('1000000.00'),
}
defaults.update(kwargs)
return Contrato.objects.create(**defaults)
Administrador de contexto para transacciones:
from django.db import transaction
with transaction.atomic():
contract = Contrato.objects.create(...)
estimate = Estimate.objects.create(contract=contract, ...)
Métodos de conjunto de consultas:
class ContratoQuerySet(models.QuerySet):
def for_company(self, company):
return self.filter(company=company)
def active(self):
return self.filter(status='active')
Herramientas#
Pelusa:
# pylint
pylint construbot/
# flake8
flake8 construbot/
Formato:
# Black (code formatter)
black .
# isort (import sorting)
isort .
Comprobación de tipo (opcional):
mypy construbot/
Ganchos de compromiso previo#
Recomendado .pre-commit-config.yaml:
repos:
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8