I want to extend my 'User' model with the 'Profile' model. To facilitate this I've created the following model. I wanted to have the linked 'Profile' model be automatically created with each new 'User' model. Based on some comments on stackoverflow / research on the internet (simpleisbetterthancomplex) I came with the following solution:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
#Pushup related stats
total_pushups = models.IntegerField(default=0)
best_consecutive = models.IntegerField(default=0)
week_streak = models.IntegerField(default=0)
save = models.IntegerField(default=000)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
However, every time I run this (whether through unit tests or 'create superuser' - I have no vies yet, I'm practicing TDD) I get the following error:
TypeError: 'int' object is not callable
Does anyone here know what I am doing wrong?
Edit: I've included a traceback of the error message that is shown after the 'create superuser' command
Traceback (most recent call last):
File "manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
utility.execute()
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/core/management/__init__.py", line 356, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/core/management/base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 63, in execute
return super(Command, self).execute(*args, **options)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 183, in handle
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/contrib/auth/models.py", line 170, in create_superuser
return self._create_user(username, email, password, **extra_fields)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/contrib/auth/models.py", line 153, in _create_user
user.save(using=self._db)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/contrib/auth/base_user.py", line 80, in save
super(AbstractBaseUser, self).save(*args, **kwargs)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/db/models/base.py", line 807, in save
force_update=force_update, update_fields=update_fields)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/db/models/base.py", line 847, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 193, in send
for receiver in self._live_receivers(sender)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 193, in <listcomp>
for receiver in self._live_receivers(sender)
File "/home/jasper/PycharmProjects/PushUpTuneUp/user_profiles/models.py", line 20, in create_user_profile
Profile.objects.create(user=instance)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/jasper/PycharmProjects/PushUpTuneUp/venv/lib/python3.5/site-packages/django/db/models/query.py", line 394, in create
obj.save(force_insert=True, using=self.db)
TypeError: 'int' object is not callable
You've defined a field called save, which is hiding the actual save method. Rename it to something else.
(And not related to your problem, but you certainly shouldn't have two receivers here. I can't see why you need the second one at all, but even if you did need that logic you should just put it in with the first one.)
Related
I'm trying to use Django's factory-bot module to create factories for my models. I'm also using pytest. I have created these factories ...
import factory
from maps.models import CoopType, Coop
from address.models import AddressField
from phonenumber_field.modelfields import PhoneNumberField
from address.models import State, Country, Locality
class CountryFactory(factory.DjangoModelFactory):
"""
Define Country Factory
"""
class Meta:
model = Country
name = "Narnia"
code = "NN"
class StateFactory(factory.DjangoModelFactory):
"""
Define State Factory
"""
class Meta:
model = State
name = "Narnia"
code = "NN"
country = CountryFactory()
class LocalityFactory(factory.DjangoModelFactory):
"""
Define Locality Factory
"""
class Meta:
model = Locality
name = "Narnia"
postal_code = "60605"
state = StateFactory()
class AddressFactory(factory.DjangoModelFactory):
"""
Define Address Factory
"""
class Meta:
model = Address
street_number = "123"
route = "Rd"
raw = "123 Fake Rd"
formatted = "123 Fake Rd."
latitude = 87.1234
longitude = -100.12342
locality = LocalityFactory()
class CoopTypeFactory(factory.DjangoModelFactory):
"""
Define Coop Type Factory
"""
class Meta:
model = CoopType
I have a very simple test file thus far. It only has one test ...
import pytest
from django.test import TestCase
from .factories import CoopTypeFactory, CoopFactory
class ModelTests(TestCase):
#classmethod
def setUpTestData(cls):
print("setUpTestData: Run once to set up non-modified data for all class methods.")
#management.call_command('loaddata', 'test_data.yaml', verbosity=0)
pass
def setUp(self):
print("setUp: Run once for every test method to setup clean data.")
#management.call_command('flush', verbosity=0, interactive=False)
pass
#pytest.mark.django_db
def test_coop_type_create(self):
""" Test customer model """ # create customer model instance
coop_type = CoopTypeFactory(name="Test Coop Type Name")
assert coop_type.name == "Test Coop Type Name"
But when I run my test, it dies complaining about a duplicate key for a factory that I'm not even creating.
davea$ python manage.py test --settings=maps.test_settings
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E
======================================================================
ERROR: tests.test_models (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: tests.test_models
Traceback (most recent call last):
File "/Users/davea/Documents/workspace/chicommons/maps/web
...
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 434, in _find_test_path
module = self._get_module_from_name(name)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 375, in _get_module_from_name
__import__(name)
File "/Users/davea/Documents/workspace/chicommons/maps/web/tests/test_models.py", line 3, in <module>
from .factories import CoopTypeFactory, CoopFactory
File "/Users/davea/Documents/workspace/chicommons/maps/web/tests/factories.py", line 19, in <module>
class StateFactory(factory.DjangoModelFactory):
File "/Users/davea/Documents/workspace/chicommons/maps/web/tests/factories.py", line 28, in StateFactory
country = CountryFactory()
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/base.py", line 46, in __call__
return cls.create(**kwargs)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/base.py", line 564, in create
return cls._generate(enums.CREATE_STRATEGY, kwargs)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/django.py", line 141, in _generate
return super(DjangoModelFactory, cls)._generate(strategy, params)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/base.py", line 501, in _generate
return step.build()
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/builder.py", line 279, in build
kwargs=kwargs,
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/base.py", line 315, in instantiate
return self.factory._create(model, *args, **kwargs)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/factory/django.py", line 185, in _create
return manager.create(*args, **kwargs)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/query.py", line 417, in create
obj.save(force_insert=True, using=self.db)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/base.py", line 729, in save
force_update=force_update, update_fields=update_fields)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/base.py", line 759, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/base.py", line 842, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/base.py", line 880, in _do_insert
using=using, raw=raw)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/query.py", line 1125, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1280, in execute_sql
cursor.execute(sql, params)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/django/db/backends/mysql/base.py", line 71, in execute
return self.cursor.execute(query, args)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/MySQLdb/cursors.py", line 209, in execute
res = self._query(query)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/MySQLdb/cursors.py", line 315, in _query
db.query(q)
File "/Users/davea/Documents/workspace/chicommons/maps/web/venv/lib/python3.7/site-packages/MySQLdb/connections.py", line 239, in query
_mysql.connection.query(self, query)
django.db.utils.IntegrityError: (1062, "Duplicate entry 'Narnia' for key 'name'")
----------------------------------------------------------------------
Ran 1 test in 0.000s
What am I doing wrong? Why is Django trying to create a factory for something I'm not creating a factory for?
You should use factory.SubFactory for defining foreign key relationships
class LocalityFactory(factory.DjangoModelFactory):
...
state = factory.SubFactory(StateFactory)
Calling the factories in your classes is creating instances
I encountered a strange behavior while applying a signal to a new model, I'm not sure to understand what is wrong but it seems related with the fact that I used abstract classes.
The models (simplified)
Basically, I have Article, Photo (inheriting from Post)
class Post(models.Model):
class Meta:
abstract = True
some_field = models.Something()
class Article(Post):
category = models.ForeignKey(Article_category, null=True, on_delete=models.SET_NULL)
some_field = models.Something()
class Photo(Post):
category = models.ForeignKey(Photo_category, null=True, on_delete=models.SET_NULL)
some_field = models.Something()
and their respective Categories
class Category(models.Model):
class Meta:
abstract = True
parent = models.ForeignKey('self', null=True, blank=True, related_name='nested_category', on_delete=models.SET_NULL)
name = models.CharField(max_length=50)
count = models.PositiveSmallIntegerField(default=0, editable=False)
class Article_category(Category):
#classmethod
def load(cls):
cache.set('{}'.format(cls.__name__), cls.objects.all())
class Photo_category(Category):
#classmethod
def load(cls):
cache.set('{}'.format(cls.__name__), cls.objects.all())
The signal
A straighforward incremental counter. Every time an article/photo is created, it's corresponding category count is updated and the entire model is saved in the cache (for templating purposes)
from django.db.models import F
#receiver(post_save, sender=Article) ----> here comes trouble
#receiver(post_save, sender=Photo)
def add_one_to_count(sender, instance, **kwargs):
cat = type(instance.category).objects.get(name=instance.category)
cat.count = F('count')+1
cat.save()
cache.set('{}_category'.format(sender.__name__), type(instance.category).objects.all())
The problem
What you saw above works like a charm for #receiver(post_save, sender=Photo) but when I add #receiver(post_save, sender=Article), DB initialization with fixture fails and I only get emptyset tables (mariaDB). This very line is the only one changing fail to success and I can't figure why. Since count is defined in the abstract class, I wondered whether it had something to do with it, for I did not have any issue applying a similar logic to categories:
# this works perfectly
#receiver(post_save, sender=Photo_category)
#receiver(post_delete, sender=Photo_category)
#receiver(post_save, sender=Article_category)
#receiver(post_delete, sender=Article_category)
def refresh_cached_category(sender, instance, using, **kwargs):
cache.set('{}'.format(type(instance).__name__), type(instance).objects.all())
Thanks for any enlightenment
The complete Traceback
Traceback (most recent call last):
File "manage.py", line 21, in <module>
main()
File "manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 72, in handle
self.loaddata(fixture_labels)
File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 114, in loaddata
self.load_label(fixture_label)
File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/loaddata.py", line 181, in load_label
obj.save(using=self.using)
File "/usr/local/lib/python3.7/site-packages/django/core/serializers/base.py", line 223, in save
models.Model.save_base(self.object, using=using, raw=True, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 790, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in send
for receiver in self._live_receivers(sender)
File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
for receiver in self._live_receivers(sender)
File "/usr/src/cms/website/observers.py", line 26, in add_one_to_count
cat = type(instance.category).objects.get(name=instance.category)
File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 408, in get
self.model._meta.object_name
website.models.DoesNotExist: Problem installing fixture '/usr/src/cms/../test/data_dev.yaml': Article_category matching query does not exist.
You can't filter on name=instance.category in your query, because that's not a str. You need to filter on name=instance.category.name but first you also need to make sure instance.category isn't None (since it can be).
The thing I don't understand is why you perform a query in the first place, just to fetch the same object: instance.category is the same as ArticleCategory.objects.get(name=instance.category.name) assuming the name is unique, except you do an extra query to the db.
Also the query will raise an exception if you have two categories with the same name (which you don't exclude in your model). So your code should be:
def add_one_to_count(sender, instance, **kwargs):
if instance.category:
instance.category.count = F('count')+1
instance.category.save()
cache.set('{}_category'.format(sender.__name__), type(instance.category).objects.all())
I'm adding a Profile to my Django app as a way to store more User information. Following https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone
However I'm getting an error when testing it. I'm using the default User model from django.contrib.auth.
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
#receiver(post_save, sender=get_user_model())
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=get_user_model())
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
tests/test_model.py
from django.test import TestCase
from app.models import Profile
class ProfileModelTests(TestCase):
#classmethod
def setUpTestData(cls):
Profile.objects.create()
def test_can_create_profile(self):
pass
error
/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
""")
..........E............
======================================================================
ERROR: setUpClass (project-api.polls.tests.test_models.ProfileModelTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
psycopg2.IntegrityError: null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (158, null).
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/test/testcases.py", line 1002, in setUpClass
cls.setUpTestData()
File "/Users/user/programming/gatsby/project-api/polls/tests/test_models.py", line 86, in setUpTestData
Profile.objects.create()
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/query.py", line 417, in create
obj.save(force_insert=True, using=self.db)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/base.py", line 729, in save
force_update=force_update, update_fields=update_fields)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/base.py", line 759, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/base.py", line 842, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/base.py", line 880, in _do_insert
using=using, raw=raw)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/query.py", line 1125, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1283, in execute_sql
cursor.execute(sql, params)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/user/.local/share/virtualenvs/project-api-HgI9cQzm/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (158, null).
----------------------------------------------------------------------
Ran 22 tests in 2.198s
FAILED (errors=1)
Using existing test database for alias 'default'...
System check identified no issues (0 silenced).
Preserving test database for alias 'default'...
#receiver(post_save, sender=get_user_model())
With this code, you are listening to the save method of the User model to create a related Profile entry just in time, if there isn't one yet. This way, you can just go along creating new Users without worrying at creating and linking Profiles manually everytime.
Note that the reverse isn't covered: if you want to create a Profile entry directly, you must pass an existing User object to it, or else you will get an IntegrityError.
Solution: preferrably, stick to one main way to create user + profile pairs; in your case, just create a User and let the signal call the creation of the profile automatically.
class ProfileModelTests(TestCase):
#classmethod
def setUpTestData(cls):
get_user_model().objects.create()
def test_profile(self):
profile = get_user_model().objects.last().profile
The idea is Profile.objects.create(user=instance) if the user doesn't exist yet an IntegrityError exception will be thrown since no user_id to be found. The signals will listen when the user will be created not the reverse.
In your testcase Profile.objects.create() will try to create a One-To-One relation with a user that doesn't exist.
I'm currently using #receiver to add a token to new users like so -
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
What I also want to be able to do is create a default WidgetList based on this model:
class WidgetList(MPTTModel):
name = models.CharField(max_length=100)
description = models.CharField(max_length=1024)
owner = models.ForeignKey('MyAppUser')
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
def __str__(self):
return self.name
class MPTTMEta:
order_insertion_by = ['name']
I tried making another reciever -
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_root_list(sender, instance=None, created=False, **kwargs):
if created:
WidgetList.objects.create(user=instance)
EDIT - on the initial python manage.py migrate I get the following traceback:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/management/__init__.py", line 351, in execute_from_command_line
utility.execute()
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/management/__init__.py", line 343, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
output = self.handle(*args, **options)
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 226, in handle
emit_post_migrate_signal(created_models, self.verbosity, self.interactive, connection.alias)
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/management/sql.py", line 280, in emit_post_migrate_signal
using=db)
File "/opt/myproject_app/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 201, in send
response = receiver(signal=self, sender=sender, **named)
File "/opt/myproject_app/lib/python2.7/site-packages/guardian/management/__init__.py", line 39, in create_anonymous_user
user.save()
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/base.py", line 734, in save
force_update=force_update, update_fields=update_fields)
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/base.py", line 771, in save_base
update_fields=update_fields, raw=raw, using=using)
File "/opt/myproject_app/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 201, in send
response = receiver(signal=self, sender=sender, **named)
File "/opt/myproject/core/models.py", line 18, in create_root_list
WidgetList.objects.create(user=instance)
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/query.py", line 346, in create
obj = self.model(**kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/mptt/models.py", line 393, in __init__
super(MPTTModel, self).__init__(*args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/base.py", line 480, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'user' is an invalid keyword argument for this function
this is the second traceback if I try to rerun migrate:
Traceback (most recent call last):
File "/opt/myproject_app/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework/viewsets.py", line 87, in view
return self.dispatch(request, *args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework_encrypted_lookup/views.py", line 41, in dispatch
return super(EncryptedLookupGenericViewSet, self).dispatch(request, *args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework/views.py", line 466, in dispatch
response = self.handle_exception(exc)
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework/views.py", line 463, in dispatch
response = handler(request, *args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework/mixins.py", line 21, in create
self.perform_create(serializer)
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework/mixins.py", line 26, in perform_create
serializer.save()
File "/opt/myproject_app/lib/python2.7/site-packages/rest_framework/serializers.py", line 191, in save
self.instance = self.create(validated_data)
File "/opt/myproject/api/serializers.py", line 106, in create
validated_data['parent'] = WidgetList.objects.get(pk=user_parent_list)
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/opt/myproject_app/lib/python2.7/site-packages/django/db/models/query.py", line 334, in get
self.model._meta.object_name
DoesNotExist: WidgetList matching query does not exist.
Comparing your traceback and your code, you can find that error happens here:
WidgetList.objects.create(user=instance)
Your model WidgetList doesn't even have user field, so it's pretty obvious that you cannot do that. Maybe you were copying & paste the code that caused an error.
There is no user in your model. Which I see you mean owner.
You will get foreign key ref errors as there is not data. Load some parent data using fixture. That would solve this issue.
I'm trying to create an admin user as part of my tests.py to check on persmissions.
UPDATE:
The tests.py is standard format that subclasses TestCase and the code below is called in the setUp() function.
I can create a normal user but not an admin user. If I try this:
self.adminuser = User.objects.create_user('admin', 'admin#test.com', 'pass')
self.adminuser.save()
self.adminuser.is_staff = True
self.adminuser.save()
OR
self.adminuser = User.objects.create_superuser('admin', 'admin#test.com', 'pass')
self.adminuser.save()
I get:
Warning: Data truncated for column 'name' at row 1
If I remove the is_staff line all is well (except I can't do my test!)
Do I have to load admin users as fixtures?
UserProfile is defined as follows:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
organisation = models.ForeignKey(Organisation, null=True, blank=True)
telephone = models.CharField(max_length=20, null=True, blank=True)
and full error traceback is:
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/test/testcases.py", line 242, in __call__
self._pre_setup()
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/test/testcases.py", line 217, in _pre_setup
self._fixture_setup()
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/test/testcases.py", line 440, in _fixture_setup
return super(TestCase, self)._fixture_setup()
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/test/testcases.py", line 222, in _fixture_setup
call_command('flush', verbosity=0, interactive=False)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/core/management/__init__.py", line 166, in call_command
return klass.execute(*args, **defaults)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/core/management/base.py", line 222, in execute
output = self.handle(*args, **options)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/core/management/base.py", line 351, in handle
return self.handle_noargs(**options)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/core/management/commands/flush.py", line 61, in handle_noargs
emit_post_sync_signal(models.get_models(), verbosity, interactive)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/core/management/sql.py", line 205, in emit_post_sync_signal
interactive=interactive)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/dispatch/dispatcher.py", line 166, in send
response = receiver(signal=self, sender=sender, **named)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/contrib/auth/management/__init__.py", line 28, in create_permissions
defaults={'name': name, 'content_type': ctype})
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/manager.py", line 123, in get_or_create
return self.get_query_set().get_or_create(**kwargs)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/query.py", line 335, in get_or_create
obj.save(force_insert=True)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/base.py", line 410, in save
self.save_base(force_insert=force_insert, force_update=force_update)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/base.py", line 495, in save_base
result = manager._insert(values, return_id=update_pk)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/manager.py", line 177, in _insert
return insert_query(self.model, values, **kwargs)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/query.py", line 1087, in insert_query
return query.execute_sql(return_id)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/sql/subqueries.py", line 320, in execute_sql
cursor = super(InsertQuery, self).execute_sql(None)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/models/sql/query.py", line 2369, in execute_sql
cursor.execute(sql, params)
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/db/backends/mysql/base.py", line 84, in execute
return self.cursor.execute(query, args)
File "build/bdist.linux-x86_64/egg/MySQLdb/cursors.py", line 175, in execute
File "build/bdist.linux-x86_64/egg/MySQLdb/cursors.py", line 89, in _warning_check
File "/usr/lib64/python2.4/warnings.py", line 61, in warn
warn_explicit(message, category, filename, lineno, module, registry)
File "/usr/lib64/python2.4/warnings.py", line 96, in warn_explicit
raise message
Warning: Data truncated for column 'name' at row 1
The answer seems to be that you can't create an admin user in setUp but you can in any other function so if you want an admin user in testing, use a fixture!
I'd use the built-in create_superuser and log the user in before making any requests. The following should work:
from django.contrib.auth.models import User
from django.test.client import Client
# store the password to login later
password = 'mypassword'
my_admin = User.objects.create_superuser('myuser', 'myemail#test.com', password)
c = Client()
# You'll need to log him in before you can send requests through the client
c.login(username=my_admin.username, password=password)
# tests go here
Update 2
Executed the snippet to create the superuser from within a test case (subclass of django.test.TestCase). Everything went fine. Also created and saved an instance of UserProfile with user = self.adminuser. That too worked.
Update
This line is interesting:
File "/usr/lib/python2.4/site-packages/Django-1.1.1-py2.4.egg/django/contrib/auth/management/__init__.py", line 28, in create_permissions
defaults={'name': name, 'content_type': ctype})
Looks like execution fails when creating permissions.
Original Answer
Warning: Data truncated for column 'name' at row 1
Strange. I tried this from the Django shell and it worked for me. I am using Postgresql 8.3 and Django 1.2.1 on Ubuntu Jaunty. Can you give more details about which version of Django/database are you using?
Also User does not have a name attribute. Can you double check if you are using auth.User?
Do I have to load admin users as fixtures?
You don't have to. But if you are creating this admin user solely for testing purposes then it would be a good idea to add a Fixture. That is what I do in my projects.