+* Changed format of attributes from a dictionary to a list of 2-tuples
+ (with backwards compatibility - previous format is deprecated).
+* Fixed small bug with names/usernames/emails sometimes not being generated in
+ corresponding sets, due to fields with unique=True not being (reliably) set
- # Enforce unique. E
ensure we don't set the same values, as either
+ # Enforce unique. Ensure we don't set the same values, as either
# any of the existing values, or any of the new ones we make up.
unique = getattr(field, 'unique', None)
If it returns False, the object will not be saved
attributes = self.get_attributes()
- for attname, replacer in attributes.items():
+ if isinstance(attributes, dict):
+ warnings.warn("The 'attributes' attribute should now be a list of tuples, not a dictionary", PendingDeprecationWarning)
+ items = attributes.items()
+ for attname, replacer in items:
self.alter_object_attribute(obj, attname, replacer)
def alter_object_attribute(self, obj, attname, replacer):
-attribute_template = " '%(attname)s'
+attribute_template = " '%(attname)s' %(replacer)s,"
skipped_template = " # Skipping field %s"
- for f in model._meta.fields:
+ fields = model._meta.fields
+ # For the faker.name/username/email magic to work as expected and produce
+ # consistent sets of names/email addreses, they must be accessed in the same
+ # order. This will usually not be a problem, but if duplicate names are
+ # produced and the field is unique=True, the logic in DjangoFaker for
+ # getting new values from the 'source' means that the order will become out
+ # of sync. To avoid this, we put fields with 'unique=True' at the beginning
+ # of the list. Usually this will only be the username.
+ sort_key = lambda f: not getattr(f, 'unique', False)
replacer = get_replacer_for_field(f)
attributes.append(skipped_template % f.attname)