Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/adgaudio/fixturefactory

Automate Django fixture creation. Easier than Factoryboy and Factorygirl!
https://github.com/adgaudio/fixturefactory

Last synced: 15 days ago
JSON representation

Automate Django fixture creation. Easier than Factoryboy and Factorygirl!

Awesome Lists containing this project

README

        

About:
===

fixturefactory is a great library for creating Django fixtures.

Within fixturefactory.py, you will find a BaseFactory and DjangoMixin.

* The BaseFactory class was written to make developing with factories for other purposes or frameworks very simple.
* The DjangoMixin class provides some methods to make fixture creation easy.

Please fork, give feedback, or add an issue to the tracker!

Use Cases:
===

Creating instances of a model

>>> ChildFactory()
>>> ChildFactory(save_to_db=False)

Create and retrieve an instance

>>> child1 = ChildFactory().last_obj_created
>>> child2 = ChildFactory()() # same as above

Dynamically passing params to your factories to override factory defaults

>>> BrotherFactory(pk1=child1.pk, pk2=1) # (params become available as class vars)

Defining your Factories:
===

All factories you create have these basic characteristics:

* Must inherit from BaseFactory (should also inherit from DjangoMixin to simplify working with Django)
* Must have a class variable, 'model', which accepts parameters and has a save() method
* Must have a method, 'getparams', which returns a dict containing the params necessary to instantiate the model
* Optionally, can have a method, 'lastly', which can be executed after model instantiation (useful for m2m)

The basic template looks like this:

class ChildFactory(BaseFactory, DjangoMixin):
model = myapp.models.SomeModel

def getparams(self):
return {}

#optional method
def lastly(self):
pass

Example Implementations:
---

The following factory generates generic Django users. A more advanced implementation may make use of randomly generated text, etc. Note that in this example, getparams returns locals(), which is a dict of the local environment. If you have defined temporary variables in the getparams() method, this approach can cause django to raise an exception, but it also brings up the point that getparams() should not do anything complicated or temporary. The purpose of getparams() is to define parameters that will eventually be used to instantiate the factory's model

class UserFactory(BaseFactory, DjangoMixin):
model = django.contrib.auth.models.User

def getparams(self):
pk = self.getUnusedPk() # Utilize the methods in DjangoMixin
username = 'markov_%s' % pk
password = 'sha1$86d38$73c3ea4bbe34f27d06b53115a8af1cd66ff263b3' # using lastly(), you can avoid encryption stuff
return locals()

#def lastly(self): pass # optional

Lets say you'd rather let django handle password encryption. The lastly() method will execute code after the object has been created. An interesting point here is that all variables defined in getparams() become available to lastly() as class variables

def lastly(self):
a = self.last_obj_created
a.set_password(self.username) # sets the password by default the defined username

Also, you can choose not to execute lastly at time of instantiation:

>>> UserProfileFactory(lastly=False)
UserProfileFactory: last_obj_created

This next example shows how to implement Foreign Keys, where the UserProfile has a Foreign Key on the above example's User model. Note that the 'user' variable in getparams() is an instance of the UserFactory's model

class UserProfileFactory(BaseFactory, DjangoMixin):
model = myapp.models.UserProfile

def getparams(self):
"""An example of a foreign key"""
user = UserFactory().last_obj_created
pk = user.pk #this User and UserProfile share the same primary key
return locals()

Implementing Many to Many Relationships are also very easy, and there are a couple different ways to do this. This example utilizes fixturefactory's 'lastly' method to execute some code after the model has been instantiated. In this case, a many to many connection is made using the instantiated model.

For this example, lets assume the UserProfile model has a many to many relationship with a model called 'Group'

class UserProfileFactory(BaseFactory, DjangoMixin):
model = myapp.models.UserProfile

def getparams(self):
return {} # lets assume you have already coded this part

def lastly(self):
"""Creating a many to many relationship after model instantiation"""
inst = self.last_obj_created
inst.groups.add(Group.objects.get(pk=1))

Here's another many to many example. If you didn't want to define a method, you can add m2m relationship after instantiation

>>> userprofile_instance = UserProfileFactory(lastly=False)()

>>> group = Group.objects.get(pk=1)
>>> userprofile_instance.groups.add(group)

If you wanted to require a parameter at runtime, your factory might look like this:

class RelatedUserFactory(BaseFactory, DjangoMixin):
model = myapp.models.RelatedUser

def getparams(self):
pk1 = self.pk1 #NOTE the class var (self.pk1) and local var (pk1) must have the same name
pk2 = self.pk2
return locals()

>>> RelatedUserFactory(pk1=3, pk2=5) #keywords 'pk1' and 'pk2' required in this case.

Development:
===

To use BaseFactory for a purpose other than Django fixtures, you'd have to (probably) override the BaseFactory.create() method. You will also probably want to create a mixin to simplify development (see DjangoMixin for an example).

Any parameters passed in to the Factory at time of instantiation are available as class variables. This is useful for mixin development,when you may need to know what parameters are overriding defaults defined by getparams().

I hope all this encourages you to use fixturefactory!