2013-06-20 1 views
4

Je viens de commencer à utiliser factory boy avec Django. Il a un paramètre FACTORY_DJANGO_GET_OR_CREATE qui signifie qu'il ne créera pas un nouvel objet s'il en existe déjà un. Mais lorsque je demande un objet existant avec un objet existant SubFactory, il crée un objet inutilisé malgré ce paramètre.Pourquoi FactoryBoy crée-t-il un nouvel objet à partir de SubFactory malgré FACTORY_DJANGO_GET_OR_CREATE

Par exemple, dans un tout nouveau projet, j'ai essayé:

# models.py 
from django.db import models 

class A(models.Model): 
    name = models.CharField(max_length=10) 

class B(models.Model): 
    name = models.CharField(max_length=10) 
    a = models.ForeignKey(A) 

Et

# factories.py 
import factory 

from . import models 

class AFactory(factory.DjangoModelFactory): 
    FACTORY_FOR = models.A 
    FACTORY_DJANGO_GET_OR_CREATE = ('name',) 

    name = factory.Sequence(lambda n: 'A-{0}'.format(n)) 

class BFactory(factory.DjangoModelFactory): 
    FACTORY_FOR = models.B 
    FACTORY_DJANGO_GET_OR_CREATE = ('name',) 

    name = factory.Sequence(lambda n: 'B-{0}'.format(n)) 
    a = factory.SubFactory(AFactory) 

maintenant:

from factories import * 

a = AFactory(name="Apple") 
models.A.objects.all() 
# one object 
b = BFactory(a__name="Apple", name="Beetle") 
models.B.objects.all() 
models.A.objects.all() 
# one A object, one B object 
b = BFactory(name="Beetle") 
models.B.objects.all() 
models.A.objects.all() 
# still one B object, but now a new, unused A object too 

Puis le dernier BFactory a mis en être un nouvel objet de classe A, même si l'objet B avec nom Beetle existe déjà (et n'est pas recréé). Pourquoi, et comment puis-je arrêter ce nouvel objet A en cours de création?

(je sais que je peux contourner ce problème en appelant à la place:

b = BFactory(name="Beetle", a__name="Apple") 

mais dans mon cas concret d'utilisation, j'ai plusieurs dépendances et les niveaux de la hiérarchie, et il est malpropre pour fournir des paramètres supplémentaires redondants de cette façon - et je n'arrive pas à obtenir la bonne combinaison de paramètres.)

Merci!

Répondre

1

Ce qui précède est un problème quand j'ai aussi une classe C qui a une clé étrangère à B. Quand j'ai créé un nouvel objet CFactory comme ceci:

c = CFactory(name="Cat", b__name="Beetle") 

il crée également un nouveau objet utilisé A.

J'ai trouvé la solution à cela est simple: au lieu, faire le nouvel objet CFactory comme ceci:

c = CFactory(name="Cat", b=b) 

b est soit un objet ou d'un objet BBFactory.

0

Je crois que la subfactory entre après le get_or_create indépendamment.

Je ne suis pas sûr d'une s9lution cependant, ce n'est pas un cas d'utilisation que j'ai rencontré. Les installations IMHO qui dépendent de get_or_create ont trop de potentiel pour la magie. L'alternative (toujours créer) peut être un peu plus fastidieuse si vous avez un cas de test compliqué, mais est plus sûr

+0

Merci! Dites A est un utilisateur et B est un message. Avec le code ci-dessus, si je crée un nouveau message, il crée toujours un nouvel utilisateur et associe le message à ce nouvel utilisateur. Puis-je utiliser 'factory boy' pour tester un utilisateur avec plusieurs messages? –

+0

J'ai réalisé que mon commentaire n'est pas clair - un utilisateur avec plusieurs messages est facile si vous définissez 'FACTORY_DJANGO_GET_OR_CREATE' comme je le fais ci-dessus.Mais j'ai en fait des utilisateurs propriétaires d'entreprises, et les entreprises font les postes (c'est-à-dire qu'il y a une troisième classe C). En fait il peut y avoir d'autres objets avec 'ForeignKeys' pour les messages aussi (classes D, E ...). Donc, chaque fois que je crée un de ces objets en aval, j'obtiens toute une hiérarchie d'objets nouvellement créés (et inutilisés). C'est ce que je voudrais éviter. –

1

Vous pouvez appeler utilisation:

a = SubFactory(AFactory, name='Reuse this model A instance') 

De cette façon, les deux invocations sont égaux:

BFactory() 
BFactory(a__name='Reuse this model A instance') 
Questions connexes