2012-04-23 2 views
10

J'utilise actuellement factory_boy pour créer des appareils dans mes tests. Factory_boy docs seulement mentionné sur SubFactory qui pourrait agir comme un champ ForeignKey dans un modèle. Cependant, il n'y avait rien sur l'association ManyToMany. Si j'avais un modèle Post suivant, comment pourrais-je créer une usine pour cela?Python factory_boy bibliothèque m2m dans le modèle Django?

class Post(models.Model): 
    title = models.CharField(max_length=100) 
    tags = models.ManyToManyField('tags.Tag') 

class PostFactory(factory.Factory): 
    FACTORY_FOR = Post 

    title = 'My title' 
    tags = ??? 
+0

Hey @Ngo avez-vous eu une réponse qui a fonctionné? – Daryl

+0

@Daryl: override _prepare semble être la solution la plus simple :) –

Répondre

2

Je n'ai pas testé, mais quel est le problème avec:

class PostFactory(factory.Factory): 
    FACTORY_FOR = Post 
    title = 'My title' 

class TagFactory(factory.Factory): 
    FACTORY_FOR = Tag 

post = PostFactory() 
tag = TagFactory() 
post.tags.add(tag) 
+1

Ouais, ça marche. Mais je voudrais faire ceci: post = PostFactory() et il y aura 4 balises ajoutées automatiquement sans avoir à spécifier manuellement post.tags.add (tag) –

+0

Je ne pense pas que factory_boy le permette. Mais pourquoi ne pas simplement créer une fonction qui fait cela pour vous? def PostFactoryWithFourTags(): post = PostFactory() pour _ en xrange (4): post.tags.add (TagFactory() retour message – Ale

7

Vous pouvez remplacer le _prepare classmethod:

class PostFactory(Factory): 
    FACTORY_FOR = Post 

    title = 'My title' 

    @classmethod 
    def _prepare(cls, create, **kwargs): 
     post = super(PostFactory, cls)._prepare(create, **kwargs) 
     if post.id: 
      post.tags = Tag.objects.all() 
     return post 

Notez que vous ne pouvez pas ajouter des balises à un message si le message n'a pas d'identifiant.

11

Qu'en est-il de post_generation hook - Je suppose que vous utilisez une version plus récente de factory_boy?

import random 
import factory 

class PostFactory(factory.Factory): 
    FACTORY_FOR = Post 
    title = factory.Sequence(lambda n: "This is test title number" + n) 
    @factory.post_generation(extract_prefix='tags') 
    def add_tags(self, create, extracted, **kwargs): 
     # allow something like PostFactory(tags = Tag.objects.filter()) 
     if extracted and type(extracted) == type(Tag.objects.all()): 
      self.tags = extracted 
      self.save() 
     else: 
      if Tag.objects.all().count() < 5: 
       TagFactory.create_batch(5, **kwargs) 
      for tag in Tag.objects.all().order_by('?')[:random.randint(1, 5)]: 
       self.tags.add(tag) 

Notez que vous pouvez utiliser PostFactory(tags__field = 'some fancy default text'), mais je recommande de créer un bon TagFactory avec ... Sequences

Vous devriez être capable de se lier PostFactory(tags = Tag.objects.filter()) mais cette partie n'a pas été testé ...

Questions connexes