Przejdź do treści

🗄️ 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

python manage.py makemigrations
python manage.py migrate

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


Ostatnia aktualizacja: 2025-11-29
Wersja dokumentacji: 1.0