🗄️ Bazy Danych - Struktura i Modele¶
Ten dokument opisuje strukturę bazy danych i modele Django.
🎯 Kluczowe koncepcje¶
BaseModel vs BaseTeamModel¶
- BaseModel - Dla modeli globalnych (np. Team, Currency)
- BaseTeamModel - Dla modeli biznesowych (np. Client, Invoice, Task)
Relacje¶
- ForeignKey - Relacja jeden-do-wielu
- ManyToMany - Relacja wiele-do-wielu
- OneToOne - Relacja jeden-do-jednego
📦 Modele bazowe¶
BaseModel¶
from apps.utils.models import BaseModel
class BaseModel(models.Model):
"""Base model with timestamps."""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
Użycie:
class Team(BaseModel):
name = models.CharField(max_length=200)
# created_at i updated_at są automatycznie dodane
BaseTeamModel¶
from apps.teams.models import BaseTeamModel
class BaseTeamModel(BaseModel):
"""Abstract model for objects that are part of a team."""
team = models.ForeignKey("teams.Team", on_delete=models.CASCADE)
class Meta:
abstract = True
Użycie:
class Client(BaseTeamModel):
name = models.CharField(max_length=200)
# team, created_at i updated_at są automatycznie dodane
🏗️ Struktura tabel¶
Kluczowe tabele¶
Teams¶
- teams_team - Zespoły (virtual tenants)
- teams_membership - Członkostwo użytkowników
- teams_invitation - Zaproszenia do zespołów
CRM¶
- crm_client - Klienci
- crm_clientcontact - Kontakty klientów
- crm_clientdocument - Dokumenty klientów
- crm_clientcontract - Umowy z klientami
Invoicing¶
- invoicing_invoice - Faktury
- invoicing_invoiceitem - Pozycje faktur
- invoicing_contractor - Kontrahenci
Tasks¶
- tasks_task - Zadania
- tasks_taskcategory - Kategorie zadań
- tasks_taskcomment - Komentarze do zadań
🔗 Relacje między modelami¶
Przykłady¶
# Client → ClientContact (1:N)
class Client(BaseTeamModel):
name = models.CharField(max_length=200)
class ClientContact(BaseTeamModel):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
# Task → User (N:1)
class Task(BaseTeamModel):
assigned_to = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=200)
# Task → TaskCategory (N:1)
class Task(BaseTeamModel):
category = models.ForeignKey(TaskCategory, on_delete=models.SET_NULL, null=True)
📊 Indeksy¶
Wymagane indeksy¶
Wszystkie tabele z team_id powinny mieć indeks:
class Meta:
indexes = [
models.Index(fields=['team', '-created_at']),
models.Index(fields=['team', 'name']),
]
Przykład¶
class Client(BaseTeamModel):
name = models.CharField(max_length=200)
nip = models.CharField(max_length=10)
class Meta:
indexes = [
models.Index(fields=['team', '-created_at']),
models.Index(fields=['team', 'nip']),
]
🔄 Migracje¶
Tworzenie migracji¶
Best Practices¶
- Nazwy migracji - Opisowe nazwy
- Reversible - Migracje powinny być odwracalne
- Data migrations - Osobne migracje dla danych
- Testowanie - Zawsze testuj migracje
🧪 Testowanie¶
Factory Boy¶
import factory
from apps.teams.models import Team
from apps.crm.models import Client
class TeamFactory(factory.django.DjangoModelFactory):
class Meta:
model = Team
name = factory.Sequence(lambda n: f"Team {n}")
slug = factory.Sequence(lambda n: f"team-{n}")
class ClientFactory(factory.django.DjangoModelFactory):
class Meta:
model = Client
team = factory.SubFactory(TeamFactory)
name = factory.Sequence(lambda n: f"Client {n}")
📚 Więcej informacji¶
- Przegląd - Ogólny przegląd architektury
- Multi-tenancy - Architektura wielodostępowa
- API - Architektura API
Ostatnia aktualizacja: 2025-11-29
Wersja dokumentacji: 1.0