2017-10-05 6 views
0

J'ai un problème avec factory boy, en cherchant J'ai trouvé un poste décrivant mon cas exact dans un autre forum, mais malheureusement sans réponses . Donc je l'ai posté ici avec impatience d'avoir une réponse à ce problème:Erreur d'usine garçon: ValueError: save() interdit pour empêcher la perte de données due à l'objet connexe non enregistré

Mon test échoue avec le message ValueError: save() prohibited to prevent data loss due to unsaved related object 'created_by' Je pense que le problème est lié à la clé étrangère.

J'essaie de tester le modèle Task, voici comment mon code ressemble

class User(AbstractUser, Entity): 

    middle_name = EnglishNameCharField(_('Middle Name'), max_length=50, blank=True, null=True) 
    birth_date = models.DateField(_('Date of Birth'), null=True) 
    gender = models.CharField(_('Gender'), max_length=2, choices=GENDER, null=True) 
    user_type= models.CharField(max_length=1, verbose_name='user type') 
    balance= models.IntegerField(verbose_name='balance', default=0) 


    objects = UserManager() 

    USERNAME_FIELD = 'username' 
    REQUIRED_FIELDS = ['first_name', 'last_name', 'email'] 

    @classmethod 
    def hidden_fields(cls): 
     fields = super(User, cls).hidden_fields() 
     return fields + ('date_joined', 
        'password', 'last_login', 'is_staff', 
        'is_active', 'is_superuser') 

    class Meta: 
     verbose_name = _('user') 
     verbose_name_plural = _('users') 

    def get_absolute_url(self): 
     return "https://stackoverflow.com/users/%s/" % urlquote(self.username) 

    def get_full_name(self): 
    """ 
    Returns the first_name plus the last_name, with a space in between. 
    """ 
     full_name = '%s %s' % (self.first_name, self.last_name) 
     if self.middle_name: 
      full_name = '%s %s %s' % (self.first_name, self.middle_name, self.last_name) 
     return full_name.strip() 

    def save(self, *args, **kwargs): 
     if self.first_name: 
      self.first_name = " ".join(x.capitalize() for x in self.first_name.split(" ")) 
     if self.last_name: 
      self.last_name = " ".join(x.capitalize() for x in self.last_name.split(" ")) 
     if self.birth_date: 
      self.age = calculate_age(self.birth_date) 
     super(User, self).save(*args, **kwargs) 


class Task(models.Model): 
    title = models.CharField(max_length=255, verbose_name='Заголовок') 
    description = models.CharField(max_length=255, verbose_name='Описание') 
    cost = models.DecimalField(max_digits=7, decimal_places=2, default=0, verbose_name='Цена') 
    assignee = models.ForeignKey('users.User', related_name='assignee', null=True, verbose_name='Исполнитель') 
    created_by = models.ForeignKey('users.User', related_name='created_by', verbose_name='Кем был создан') 

    def __str__(self): 
     return self.title 

je test avec garçon usine qui est de savoir comment ma classe garçon d'usine ressemble

class UserFactoryCustomer(factory.Factory): 

    class Meta: 
     model = User 

    first_name = 'name' 
    last_name = 'Asadov' 
    username = factory.LazyAttribute(lambda o: slugify(o.first_name + '.' + o.last_name)) 
    email = factory.LazyAttribute(lambda a: '{0}.{1}@example.com'.format(a.first_name, a.last_name).lower()) 
    user_type = 1 
    balance = 10000.00 

class UserFactoryExecutor(factory.Factory): 

    class Meta: 
     model = User 

    first_name = 'Uluk' 
    last_name = 'Djunusov' 
    username = factory.LazyAttribute(lambda o: slugify(o.first_name + '.' + o.last_name)) 
    email = factory.LazyAttribute(lambda a: '{0}.{1}@example.com'.format(a.first_name, a.last_name).lower()) 
    user_type = 2 
    balance = 5000.00 


class TaskFactory(factory.Factory): 

    class Meta: 
     model = Task 

    title = factory.Sequence(lambda n: 'Title {}'.format(n)) 
    description = factory.Sequence(lambda d: 'Description {}'.format(d)) 
    cost = 5000.00 
    assignee = factory.SubFactory(UserFactoryExecutor) 
    created_by = factory.SubFactory(UserFactoryCustomer) 

C'est le exemple de mon test

class ApiModelTestCase(TestCase): 

    def test_creating_models_instance(self): 
     executor = factories.UserFactoryExecutor() 
     customer = factories.UserFactoryCustomer() 
     Task.objects.create(title="Simple Task", description="Simple Description", cost="5000.00", 
         assignee=executor, created_by=customer) 

Ceci est l'erreur affichée dans la console:

ERROR: test_creating_models_instance (tests.test_models.ApiModelTestCase) 

Traceback (most recent call last): 
    File "/Users/heartprogrammer/Desktop/freelance-with-api/freelance/tests/test_models.py", line 12, in test_creating_models_instance 
    assignee=executor, created_by=customer) 
    File "/Users/heartprogrammer/Documents/envs/freelance/lib/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method 
return getattr(self.get_queryset(), name)(*args, **kwargs) 
    File "/Users/heartprogrammer/Documents/envs/freelance/lib/python3.6/site-packages/django/db/models/query.py", line 394, in create 
obj.save(force_insert=True, using=self.db) 
    File "/Users/heartprogrammer/Documents/envs/freelance/lib/python3.6/site-packages/django/db/models/base.py", line 763, in save 
"unsaved related object '%s'." % field.name 
ValueError: save() prohibited to prevent data loss due to unsaved related object 'assignee'. 

Des idées?

+0

Est-ce que cela fait une différence si vous supprimez les guillemets de 'cost =" 5000.00 "'? Je me rends compte que cela ne semble pas être lié au message d'erreur, mais de toute façon les citations ne devraient pas être là. – evergreen

+0

Pouvez-vous également publier votre code de modèle utilisateur? Et y a-t-il autre chose dans le modèle, comme un post-sauvegarde? –

+0

En outre, le message d'erreur est moins informatif que ce pourrait être parce que votre nom-related est le même que le field_name pour assigné et created_by. Pouvez-vous les passer à tasks_created et tasks_assigned ou quelque chose, lors du référencement de l'utilisateur? –

Répondre

0

Je déteste le rompre pour vous, mais je pense que cela est un problème d'indentation manquer ...

La super(User, self).save(*args, **kwargs) partie de votre méthode save pour l'utilisateur est pas réellement dans la méthode Save. C'est pourquoi ce n'est pas vraiment sauvé.

+0

c'était une erreur de copier pate le code .. L'utilisateur est enregistré correctement dans l'application web –

+0

Quelle version d'usine utilisez-vous? Mettre à jour peut aider si c'est vieux. Et si c'est 2.9.x, essayez de revenir à la version 2.8.x car ils ont fait un gros changement interne récemment. Bien que ce ne soit pas une bonne réponse. –

+0

sa version est «2.8.1»: / –