2015-03-01 2 views
1

J'utilise Factory Boy dans mon projet Django. Pourriez-vous m'expliquer mon erreur: pourquoi ai-je l'erreur quand j'ai lancé 'tests.py' - 'ValueError: "" doit avoir une valeur pour le champ "post" avant que cette relation many-to-many puisse être utilisée . 'Erreur dans le test Django en utilisant Factory Boy

Voici mon code:

import factory 

from . import models 

# factories 


class TagFactory(factory.Factory): 
    class Meta: 
     model = models.Tag 

    name = factory.Sequence(lambda n: 'tag-%s' % n) 
    slug = factory.Sequence(lambda n: 'slug-%s' % n) 


class CategoryFactory(factory.Factory): 
    class Meta: 
     model = models.Category 

    name = factory.Sequence(lambda n: 'cat-%s' % n) 
    slug = factory.Sequence(lambda n: 'cat-slug-%s' % n) 


class PostFactory(factory.Factory): 
    class Meta: 
     model = models.Post 

    title = factory.Sequence(lambda n: 'postik-%s' % n) 
    text = 'some text' 
    slug = factory.Sequence(lambda n: 'post_slug_%s' % n) 
    category = factory.SubFactory(CategoryFactory) 

    @factory.post_generation 
    def tags(self, create, extracted, **kwargs): 
     if not create: 
      # Simple build, do nothing. 
      return 
     if extracted: 
      for tag in extracted: 
       self.tags.add(tag) 

tests.py

from django.test import TestCase 

from . import factories 
from .models import Post, Category, Tag 
from django.core.urlresolvers import reverse 


class PostTests(TestCase): 
    """ 
    display_post view test. 
    """ 
    def setUp(self): 
     self.tag = factories.TagFactory() 
     self.category = factories.CategoryFactory() 
     self.poster = factories.PostFactory.create(tags=('tag-1')) 

... 

models.py

from django.db import models 
from django.core.urlresolvers import reverse 
from django.utils import timezone 
from django.utils.translation import ugettext_lazy as _ 

from ckeditor.fields import RichTextField 


class Category(models.Model): 
    """ 
    Category. 
    """ 

    name = models.CharField(max_length=20) 
    slug = models.SlugField(max_length=20) 

    def __str__(self): 
     return self.name 

    def get_absolute_url(self): 
     return reverse('categorier', args=[str(self.slug)]) 


class Tag(models.Model): 
    """ 
    Tag. 
    """ 

    name = models.CharField(max_length=100, unique=True) 
    slug = models.SlugField(max_length=100, unique=True) 

    def __str__(self): 
     return self.name 

    def get_absolute_url(self): 
     return reverse('tagger', args=[str(self.slug)]) 

    class Meta: 
     verbose_name = _('Tag') 


class Post(models.Model): 
    """ 
    Post model. 
    """ 

    title = models.CharField(max_length=150) 
    created_date = models.DateTimeField(auto_now_add=True) 
    image = models.ImageField(upload_to="pictures/%Y/%m/%d", 
             blank=True, null=True) 
    text = RichTextField(max_length=10000) 
    slug = models.SlugField(max_length=150, unique=True) 
    tags = models.ManyToManyField(Tag, null=True, blank=True) 
    category = models.ForeignKey(Category) 

    def __str__(self): 
     return self.title 

    def get_absolute_url(self): 
     return reverse('poster', args=[str(self.slug)]) 

    class Meta: 
     ordering = ['-created_date'] 
     verbose_name = _('Eco Post') 
     verbose_name_plural = _('Eco Posts') 

Traceback:

ERROR: test_display_post (posts.tests.PostTests) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/ecohata/posts/tests.py", line 17, in setUp 
    self.poster = factories.PostFactory.create(tags=('tag-1')) 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/lib/python3.4/site-packages/factory/base.py", line 585, in create 
    return cls._generate(True, attrs) 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/lib/python3.4/site-packages/factory/base.py", line 516, in _generate 
    results[name] = decl.call(obj, create, extraction_context) 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/lib/python3.4/site-packages/factory/declarations.py", line 490, in call 
    extraction_context.value, **extraction_context.extra) 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/ecohata/posts/factories.py", line 41, in tags 
    self.tags.add(tag) 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/lib/python3.4/site-packages/django/db/models/fields/related.py", line 1175, in __get__ 
    through=self.field.rel.through, 
    File "/Users/boshepelinski/Documents/Projects/Django/ecohata/lib/python3.4/site-packages/django/db/models/fields/related.py", line 831, in __init__ 
    (instance, source_field_name)) 
ValueError: "<Post: postik-0>" needs to have a value for field "post" before this many-to-many relationship can be used. 

Répondre

3

Le correctif est assez simple: vos usines héritent de factory.Factory, mais vous utilisez des modèles Django. Vous devriez hériter de factory.django.DjangoModelFactory à la place.

Sinon, factory_boy ne sait pas qu'il doit save() vos objets une fois généré, et vous obtenez l'échec par la suite.

Vous avez également un autre problème dans votre code: lorsque vous écrivez factories.PostFactory.create(tags=('tag-1')), c'est en fait la même chose que d'écrire factories.PostFactory.create(tags='tag-1).

Cependant:

  • La définition de votre déclaration @post_generation balises attend une liste des balises, vous devez donc utiliser factories.PostFactory.create(tags=['tag-1'])
  • En fait, puisqu'il appelle self.tags.add(tag), il attend un itérables de Tag objets; il devrait être appelé par factories.PostFactory.create(tags=[TagFactory()]).
+0

Merci beaucoup, Xelnor! – jwshadow

+0

Je suis tombé dans le même problème que @jwshadow parce que je suppose que nous deux suivions la même [recette] (https://factoryboy.readthedocs.io/en/latest/recipes.html#simple-many-to-many -relationship) dans la page Factory Boy. Devrions-nous soumettre une correction dans la documentation? – luizs81