Vorweg klar: Faker ist eine großartige Bibliothek. Wenn du einen plausiblen Namen, eine E-Mail, eine Adresse oder einen Zeitstempel brauchst, nimm sie. Das Problem sind nicht die Werte. Das Problem ist, dass Faker jeden Wert unabhängig erzeugt, und eine echte Datenbank ist das genaue Gegenteil von unabhängig.
Der Bruch, in einem Snippet
Angenommen, du fakest Nutzer, Bestellungen und Bestellpositionen in Python:
from faker import Faker
fake = Faker()
users = [{"id": i, "name": fake.name(), "email": fake.email()} for i in range(1, 1001)]
orders = [{"id": i,
"user_id": fake.random_int(min=1, max=1000),
"total": fake.pydecimal(left_digits=4, right_digits=2, positive=True)}
for i in range(1, 5001)]
items = [{"id": i,
"order_id": fake.random_int(min=1, max=5000),
"product_id": fake.random_int(min=1, max=200),
"quantity": fake.random_int(min=1, max=5)}
for i in range(1, 20001)]
Läuft durch, und die Zeilen sehen gut aus. Dann lädst du sie mit aktivierten Constraints in eine echte Datenbank:
ERROR: insert or update on table "order_items" violates
foreign key constraint "order_items_product_id_fkey"
DETAIL: Key (product_id)=(173) is not present in table "products".
Es gibt hier gar keine products-Tabelle, product_id zeigt also ins Leere. Und das ist noch der gute Fall, in dem der Fehler offensichtlich ist.
Die vier Dinge, die bei Masse brechen
1. Fremdschlüssel zeigen auf Zeilen, die es nicht gibt
Der random_int(min=1, max=1000)-Trick funktioniert nur, wenn die Eltern-IDs exakt 1..1000 sind, ohne Lücken, vor den Kindern erzeugt, und du jeden Bereich für jede Beziehung von Hand begrenzt. Sobald deine Keys UUIDs sind, es Lücken gibt oder ein Eltern-Set gefiltert ist, ist der Trick weg. Faker hat kein Konzept von "einer ID, die bereits existiert".
2. Nichts ist in Insert-Reihenfolge
Ein echtes Laden muss users vor orders einfügen und orders vor order_items. Faker gibt dir drei unabhängige Listen. Entweder sortierst du den Abhängigkeitsgraph selbst topologisch, oder du deaktivierst die Constraints beim Laden, was bedeutet, dass du Daten ausspielst, die in Produktion nie existieren könnten.
3. Die Verteilung ist gleichförmig, Produktion ist es nie
Weil jede user_id gleichverteilt zufällig ist, bekommt jeder Nutzer ungefähr gleich viele Bestellungen. Echte Daten haben einen langen Schwanz: die meisten haben ein, zwei, ein paar haben Dutzende. Genau dieser Schwanz ist, wo Pagination, N+1-Queries und langsame Joins umkippen. Gleichförmige Fake-Daten verstecken genau die Bugs, die du finden willst.
4. Werte sind über Spalten hinweg inkohärent
Faker füllt jede Spalte für sich, die E-Mail passt also nicht zum Namen (fake.name() gibt "Alex Miller", fake.email() gibt "wsmith@example.org"), und order.total hat keinen Bezug zur Summe seiner Positionen. Jeder Test, der einen abgeleiteten oder denormalisierten Wert prüft, ist damit wertlos.
fake.email() und reißt eine UNIQUE-Constraint. Wechselst du zu fake.unique.email(), erschöpft Faker irgendwann seinen Pool und wirft UniquenessException. So oder so schreibst du Retry-Logik um einen Datengenerator herum.Was du eigentlich willst
Du willst Daten, die per Konstruktion referenziell konsistent sind: Kinder referenzieren nur existierende Eltern, Inserts kommen Eltern-zuerst, Verteilungen sind schief wie im echten Leben, und abgeleitete Werte sind rekonziliert. Das ist kein Faker-Aufruf, das ist eine Eigenschaft des ganzen Datensatzes, abgeleitet aus deinem Schema.
Genau diese Linie zieht SeedBase. Du gibst dein Schema rein (SQL, eine Django-models.py oder ein Prisma-Schema) und es:
- löst jeden Fremdschlüssel gegen wirklich erzeugte Zeilen auf, UUIDs und Lücken inklusive;
- ordnet Inserts topologisch, sodass es mit aktivierten Constraints lädt;
- verteilt Kind-Anzahlen in einen langen Schwanz und hält Werte kohärent (E-Mail passt zum Namen,
order.totalentspricht seinen Positionen); - ist pro Seed deterministisch, ein CI-Lauf ist also reproduzierbar.
Die Kurzfassung
Faker macht großartige Werte und null Garantien darüber, wie sie zusammenpassen. Für eine einzelne Spalte ist das alles, was du brauchst. Für eine Datenbank mit Beziehungen sind "gültiger Wert pro Zelle" und "gültiger Datensatz" verschiedene Probleme, und nur das zweite lädt.
Daten, die wirklich laden
Zeig SeedBase dein Schema und generiere eine befüllte, FK-konsistente Datenbank mit realistischen Verteilungen. Free-Tier, keine Kreditkarte.
- Jeder FK geht auf
- Long-Tail-Verteilungen
- SQL / CSV / JSON
- EU-gehostet
Mehr: SeedBase vs Faker · Django-DB befüllen · Testdaten generieren