55👍
If you subclass factory.DjangoModelFactory it should save the user object for you. See the note section under PostGenerationMethodCall. Then you only need to do the following:
class UserFactory(factory.DjangoModelFactory):
FACTORY_FOR = User
email = 'admin@admin.com'
username = 'admin'
password = factory.PostGenerationMethodCall('set_password', 'adm1n')
is_superuser = True
is_staff = True
is_active = True
13👍
I am using Django 1.11 (I can bet it will work in Django 2+) and factory_boy 2.11.1. This was pretty simple:
import factory
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User
class SuperUserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')
username = factory.Faker('email')
password = factory.LazyFunction(lambda: make_password('pi3.1415'))
is_staff = True
is_superuser = True
In this example, all users will have password 'pi3.1415'
change it accordingly if you want something different, or you can even use password = factory.Faker('password')
to generate a random password (however, it should be something you are able to figure out. Otherwise, it will be very hard to log in).
Example creating a superuser
>>> user = SuperUserFactory.create()
>>> user.username # the following output will be different in your case
amber60@hotmail.com
Use the email you got from user.username
and the password 'pi3.1415'
to log in in the admin.
What if the user has reverse foreign keys associated?
Simple, let’s say you have a model Profile
which has a foreign key to your User
model. Then you have to add the following classes:
class Profile(models.Model):
user = models.OneToOneField(User)
visited = models.BooleanField(default=False)
# You need to set the foreign key dependency using factory.SubFactory
class ProfileFactory(factory.django.DjangoModelFactory):
class Meta:
model = Profile
user = factory.SubFactory(UserFactory)
# use a RelatedFactory to refer to a reverse ForeignKey
class SuperUserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')
username = factory.Faker('email')
password = factory.LazyFunction(lambda: make_password('pi3.1415'))
is_staff = True
is_superuser = True
profile = factory.RelatedFactory(ProfileFactory, 'user', visited=True)
That’s it, use the same logic in the example to create your superuser.
- [Django]-Django-orm case-insensitive order by
- [Django]-TemplateDoesNotExist – Django Error
- [Django]-IOS app with Django
8👍
Creating admin users:
You can add a Params declaration that provides flexibility to quickly create an admin user or a normal user.
Setting raw passwords:
In order to ensure that the password param gets set as a raw unencrypted value, you can use Django’s set_password to set a raw password after the initial save in the _create classmethod override.
https://docs.djangoproject.com/en/2.1/ref/contrib/auth/#django.contrib.auth.models.User.set_password
class UserFactory(factory.django.DjangoModelFactory):
first_name = factory.Faker('first_name')
last_name = factory.Faker('last_name')
username = factory.Sequence(lambda n: 'demo-user-%d' % n)
is_staff = False
is_superuser = False
password = 'secret'
@factory.lazy_attribute
def email(self):
return '%s@test.com' % self.username
class Meta:
model = User
class Params:
# declare a trait that adds relevant parameters for admin users
flag_is_superuser = factory.Trait(
is_superuser=True,
is_staff=True,
username = factory.Sequence(lambda n: 'admin-%d' % n),
)
@classmethod
def _create(cls, model_class, *args, **kwargs):
password = kwargs.pop("password", None)
obj = super(UserFactory, cls)._create(model_class, *args, **kwargs)
# ensure the raw password gets set after the initial save
obj.set_password(password)
obj.save()
return obj
Usage:
# This admin user can log in as "admin-1", password "secret"
admin = UserFactory.create(flag_is_superuser=True)
# This regular user can log in as "userABC", password "secretABC"
user = UserFactory.create(username="userABC", password="secretABC")
Using factory-boy v2.11.1 and Django v1.11.6
- [Django]-How to add superuser in Django from fixture
- [Django]-Twisted server crashes unexpectedly while running django
- [Django]-Internal Server Error with Django and uWSGI
7👍
I’m assuming you’re working on the http://www.tdd-django-tutorial.com tutorial because that’s where I got stuck as well. You probably figured this out by now, but for the next person, here’s the code that worked for me, the trick was adding the _prepare method to ensure password is encrypted, and setting all the flags to true (This was done with Django 1.5.1, if you’re using an earlier version, change the User model imports)
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import factory
from django.contrib.auth import get_user_model
User = get_user_model()
class UserFactory(factory.DjangoModelFactory):
FACTORY_FOR = User
email = 'admin@admin.com'
username = 'admin'
password = 'adm1n'
is_superuser = True
is_staff = True
is_active = True
@classmethod
def _prepare(cls, create, **kwargs):
password = kwargs.pop('password', None)
user = super(UserFactory, cls)._prepare(create, **kwargs)
if password:
user.set_password(password)
if create:
user.save()
return user
class PollsTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(3)
self.user = UserFactory.create()
def tearDown(self):
self.browser.quit()
def test_can_create_new_poll_via_admin_site(self):
self.browser.get(self.live_server_url+'/admin/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Django administration', body.text)
username_field = self.browser.find_element_by_name('username')
username_field.send_keys(self.user.username)
password_field = self.browser.find_element_by_name('password')
password_field.send_keys('adm1n')
password_field.send_keys(Keys.ENTER)
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Site administration', body.text)
polls_links = self.browser.find_element_by_link_text('Polls')
self.assertEqual(len(polls_links), 2)
self.fail('Finish the test!')
- [Django]-How to TRUNCATE TABLE using Django's ORM?
- [Django]-Django migration with uuid field generates duplicated values
- [Django]-Raise 404 and continue the URL chain
5👍
I had a similar problem when created a user. Django hash passwords when creates a user and you save the password using DjangoFactory without hash. On login Django checks password that you send with stored hash one. On this step verification fails as you check not hashed password with a not hashed password. Here is an example how I fixed this in my code:
from django.contrib.auth.hashers import make_password
from factory import DjangoModelFactory, Sequence
class UserFactory(DjangoModelFactory):
class Meta:
model = User
django_get_or_create = ('username', 'password')
username = Sequence(lambda n: 'somename%s' % n)
password = Sequence(lambda p: 'mysuperpass%s' % p)
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Override the default ``_create`` with our custom call."""
kwargs['password'] = make_password(kwargs['password'])
return super(UserFactory, cls)._create(model_class, *args, **kwargs)
I take password that was generated using Sequence and hash it using Django make_password
method. In tests you can create a var with not hashed value and create a user with this var.
Example:
password = 'test123'
user = UserFactory(password=my_password)
- [Django]-How can I handle Exceptions raised by dango-social-auth?
- [Django]-Exclude fields in Django admin for users other than superuser
- [Django]-ImportError: cannot import name '…' from partially initialized module '…' (most likely due to a circular import)
1👍
This way I think you preserve the behavior you expect in your code, this way you have a default value for password and also you can override it with any value you want when calling UserFactory.
class UserFactory(factory.Factory):
FACTORY_FOR = User
username = 'jeff'
password = 'pass'
is_superuser = True
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Create an instance of the model, and save it to the database."""
if cls._meta.django_get_or_create:
return cls._get_or_create(model_class, *args, **kwargs)
manager = cls._get_manager(model_class)
return manager.create_user(*args, **kwargs) # Just user the create_user method recommended by Django
- [Django]-Django – Getting last object created, simultaneous filters
- [Django]-Django File upload size limit
- [Django]-How to create an empty queryset and to add objects manually in django