Reputation: 6575
I have 3 models on the same module, app.models.py
, as following. Some other models may appear in code but it isn't relevant.
Optionals
class Optional(models.Model):
name = models.CharField(_('Nome'), max_length=255)
type = models.CharField(_('Tipo'), max_length=50, null=True, blank=True)
description = models.TextField(_('Descrição'), null=True, blank=True)
provider = models.ForeignKey('providers.Provider', null=True, blank=True)
charge = models.ForeignKey('Charge', null=True, blank=True)
def __str__(self):
return self.name
Coverage
class Coverage(models.Model):
code = models.CharField(_('Código'), max_length=20, null=True, blank=True)
vehicle_code = models.CharField(_('Código do veículo (ACRISS)'), max_length=4, null=True, blank=True)
charge = models.ForeignKey('Charge', null=True, blank=True)
Vehicle
class Vehicle(models.Model):
code = models.CharField(_('Código'), max_length=100)
description = models.CharField(_('Descrição'), max_length=255, null=True, blank=True)
model = models.CharField(_('Modelo'), max_length=100, null=True, blank=True)
brand = models.CharField(_('Fabricante'), max_length=100, null=True, blank=True)
group = models.ForeignKey('Group', null=True, blank=True)
optionals = models.ManyToManyField('Optional', related_name='vehicle_optional')
coverages = models.ManyToManyField('Coverage', related_name='vehicle_coverage')
def __str__(self):
return self.code
I'm trying create fixtures from this models using factory_boy.
class CoverageFactory(factory.Factory):
class Meta:
model = Coverage
charge = factory.SubFactory(ChargeFactory)
class OptionalFactory(factory.Factory):
class Meta:
model = Optional
provider = factory.SubFactory(ProviderFactory)
charge = factory.SubFactory(ChargeFactory)
class VehicleFactory(factory.Factory):
class Meta:
model = Vehicle
group = factory.SubFactory(GroupFactory)
optionals = factory.SubFactory(OptionalFactory)
coverages = factory.SubFactory(CoverageFactory)
On my tests it is instantiated this way:
optional = OptionalFactory(
name="GPS",
type="13",
description="",
charge=charge,
provider=provider
)
coverage = CoverageFactory(
code="ALI",
vehicle_code="ABCD",
charge=charge
)
vehicle = VehicleFactory(
code="ECMM",
description="GRUPO AX - MOVIDA ON",
model="MOBI LIKE, OU SIMILAR",
brand="",
optionals=optional,
coverages=coverage
)
And when I run tests, with pytest-django, I get this error.
ValueError: "<Vehicle: ECMM>" needs to have a value for field "id" before this many-to-many relationship can be used.
I've read the factory_boy docs about Simple Many-to-many relationship and Many-to-many relation with a ‘through’ but can't fix.
Upvotes: 1
Views: 1935
Reputation: 83
You've already pointed to the correct place in the docs, which should work: https://factoryboy.readthedocs.io/en/latest/recipes.html#simple-many-to-many-relationship
class VehicleFactory(factory.Factory):
...
# no optionals subfactory here
...
@factory.post_generation
def optionals(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
# A list of groups were passed in, use them
for optional in extracted:
self.groups.add(optional)
Then you'd call with something like:
VehicleFactory.create(optionals=[optional1, optional2])
Hopefully that answers the question? It's hard to be more helpful without more information about what didn't work when you tried the solution in the docs
Upvotes: 1
Reputation: 3512
When calling UserFactory() or UserFactory.build(), no group binding will be created.
But when UserFactory.create(groups=(group1, group2, group3)) is called, the groups declaration will add passed in groups to the set of groups for the user.
the id
field will be generated when you
optional = OptionalFactory.create( # note the .create()
name="GPS",
type="13",
description="",
charge=charge,
provider=provider
)
Then when you
vehicle = VehicleFactory.create(
...
optionals=(optional,),
)
The many-to-many optionals
can be established. Notes also the arguments to optionals is (optionals,)
. The function expect an iterable
Upvotes: 1