Authtoken migration not working despite unit test functioning - python

I'm adding TokenAuthentication to our django project. All was going well, and I've added a migration and unit test for the token auth:
# Migration
from django.db import migrations
def create_missing_tokens(apps, schema_editor):
"""
Tokens were added in 0002_auto_20160226_1747, we thus need to populate
the tokens table for existing users
"""
Token = apps.get_model('authtoken', 'Token')
User = apps.get_model('accounts', 'CustomUser')
for user in User.objects.all():
Token.objects.get_or_create(user=user)
class Migration(migrations.Migration):
dependencies = [
# depends on authtoken migration
('accounts', '0003_subscription_max_updates_per_day'),
('authtoken', '0002_auto_20160226_1747'), # latest migration in the authtoken package
]
operations = [
migrations.RunPython(create_missing_tokens, reverse_code=migrations.RunPython.noop),
]
# unit test
class MigrationTestCase(TransactionTestCase):
'''A Test case for testing migrations'''
# These must be defined by subclasses.
migrate_from = None
migrate_to = None
def setUp(self):
super(MigrationTestCase, self).setUp()
self.executor = MigrationExecutor(connection)
self.executor.migrate(self.migrate_from)
def migrate_to_dest(self):
self.executor.loader.build_graph() # reload.
self.executor.migrate(self.migrate_to)
#property
def old_apps(self):
return self.executor.loader.project_state(self.migrate_from).apps
#property
def new_apps(self):
return self.executor.loader.project_state(self.migrate_to).apps
from accounts.models import CustomUserManager
class SummaryTestCase(MigrationTestCase):
"""
We need to test that data is populated in the summary field on running the migration
"""
migrate_from = [('accounts', '0003_subscription_max_updates_per_day')]
migrate_to = [('accounts', '0004_create_tokens')]
def setup_before_migration(self):
manager = CustomUserManager()
User = self.old_apps.get_model('accounts', 'CustomUser')
manager.model = User
manager.create_user(email='contact#a.fr', # nosec
password='kjnfrkj',
)
def test_token_populated(self):
# runs setup
self.setup_before_migration()
# now migrate
self.migrate_to_dest()
# grab new models
Token = self.new_apps.get_model('authtoken', 'Token')
User = self.new_apps.get_model('accounts', 'CustomUser')
for user in User.objects.all():
self.assertTrue(Token.objects.filter(user_id=user.pk).exists())
This works great, but when i actually run the migration i get the message:
django.db.utils.IntegrityError: duplicate key value violates unique
constraint "authtoken_token_pkey" DETAIL: Key (key)=() already
exists.
Here is some pseudo code for what i mean by "actually run the migration":
$ git checkout <old commit> # grab old commit
$ ./run.sh go # spin up docker with server and db
$ git checkout master # which includes migrations
$ ./run.sh again # log into docker image with django
$ (docker) python manage.py migrate # run the migrations
the error i see is thus (full stack trace at the end of the question):
django.db.utils.IntegrityError: duplicate key value violates unique constraint "authtoken_token_pkey"
DETAIL: Key (key)=() already exists.
I cant understand how with a migration that uses Token.objects.get_or_create(user=user) I'm getting a duplicate key? any help would be greatly appreciated
Applying accounts.0004_create_tokens...Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 538, in get_or_create
return self.get(**kwargs), False
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 408, in get
self.model._meta.object_name
__fake__.DoesNotExist: Token matching query does not exist.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "authtoken_token_pkey"
DETAIL: Key (key)=() already exists.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 15, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.6/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.6/site-packages/django/core/management/base.py", line 323, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 364, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 83, in wrapped
res = handle_func(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 234, in handle
fake_initial=fake_initial,
File "/usr/local/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/usr/local/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/usr/local/lib/python3.6/site-packages/django/db/migrations/executor.py", line 245, in apply_migration
state = migration.apply(state, schema_editor)
File "/usr/local/lib/python3.6/site-packages/django/db/migrations/migration.py", line 124, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/usr/local/lib/python3.6/site-packages/django/db/migrations/operations/special.py", line 190, in database_forwards
self.code(from_state.apps, schema_editor)
File "/code/accounts/migrations/0004_create_tokens.py", line 12, in create_missing_tokens
Token.objects.get_or_create(user=user)
File "/usr/local/lib/python3.6/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.6/site-packages/django/db/models/query.py", line 541, in get_or_create
return self._create_object_from_params(kwargs, params)
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 583, in _create_object_from_params
raise e
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 575, in _create_object_from_params
obj = self.create(**params)
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 422, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 779, in save_base
force_update, using, update_fields,
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 870, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 908, in _do_insert
using=using, raw=raw)
File "/usr/local/lib/python3.6/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.6/site-packages/django/db/models/query.py", line 1186, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1335, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 99, in execute
return super().execute(sql, params)
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: duplicate key value violates unique constraint "authtoken_token_pkey"
DETAIL: Key (key)=() already exists.
EDIT: Custom user class is nothing special, looks like this:
class CustomUser(AbstractUser):
"""
Replace username by email as required and unique.
"""
is_alphanumeric_or_dash = RegexValidator(r'^[0-9a-zA-Z\-]*$', 'Only alphanumeric and "-" characters are allowed.')
# Hide username
username = None
# Overidde other fields
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'),
max_length=100,
blank=True,
validators=[is_alphanumeric_or_dash])
last_name = models.CharField(_('last name'),
max_length=100,
blank=True,
validators=[is_alphanumeric_or_dash])
# /!\ At some point, user should have a default subcription /!\
subscription = models.ForeignKey(Subscription, on_delete=models.PROTECT, blank=True, null=True)
# some other fields, but nothing special...
USERNAME_FIELD = 'email'
# Override the UserManager with our custom one (for objects creation)
objects = CustomUserManager()

A Token's key is normally generated by its save() method. This is fine when you're generating the tokens manually but in a migration, where you're referencing the model via apps.get_model(), none of the custom model methods are available.
So what's happening is that the tokens are being generated with empty keys. The first one will work but all after that will generate this error because the key is not unique.
A simple workaround is to just copy the code that DRF uses to generate the key into your migration. Something like this should work:
for user in User.objects.using(db_alias).all():
key = binascii.hexlify(os.urandom(20)).decode()
Token.objects.using(db_alias).get_or_create(user=user, key=key)

Related

Django - Variable deleting itself prior to Object Create?

Consider this snippet:
if fire_prim is not None:
print('Fire Primary is definitely not Null, here is proof: {}'.format(fire_prim))
fire_primary_obj = LifeSafety.objects.create(
name='Fire Primary',
store=store_obj,
phone_line=fire_prim,
phone_line_provider=an_provider)
We get the following output:
Fire Primary is definitely not Null, here is proof: +16077244546
Traceback (most recent call last):
File "C:\Python\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "C:\Python\lib\site-packages\django\db\backends\sqlite3\base.py", line 298, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: stores_lifesafety.phone_line
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Users\admin-dksc104694\Desktop\Dev\it-database\scripts\data.py", line 246, in update_lifesafety_devices
fire_primary_obj = LifeSafety.objects.create(name='Fire Primary', store=store_obj, phone_line=fire_prim, phone_line_provider=an_provider)
File "C:\Python\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Python\lib\site-packages\django\db\models\query.py", line 413, in create
obj.save(force_insert=True, using=self.db)
File "C:\Python\lib\site-packages\django\db\models\base.py", line 718, in save
force_update=force_update, update_fields=update_fields)
File "C:\Python\lib\site-packages\django\db\models\base.py", line 748, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "C:\Python\lib\site-packages\django\db\models\base.py", line 831, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "C:\Python\lib\site-packages\django\db\models\base.py", line 869, in _do_insert
using=using, raw=raw)
File "C:\Python\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Python\lib\site-packages\django\db\models\query.py", line 1136, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "C:\Python\lib\site-packages\django\db\models\sql\compiler.py", line 1289, in execute_sql
cursor.execute(sql, params)
File "C:\Python\lib\site-packages\django\db\backends\utils.py", line 100, in execute
return super().execute(sql, params)
File "C:\Python\lib\site-packages\django\db\backends\utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "C:\Python\lib\site-packages\django\db\backends\utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "C:\Python\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "C:\Python\lib\site-packages\django\db\utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "C:\Python\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "C:\Python\lib\site-packages\django\db\backends\sqlite3\base.py", line 298, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: stores_lifesafety.phone_line
We can see with 100% certainty that the line just before object creation, fire_prim has a value of +16077244546 which should serve as the phone_line, but by the time it gets to creation its deleted somehow.
Here is my model for reference:
class LifeSafety(models.Model):
name = models.CharField(max_length=40, default='unspecified')
store = models.ForeignKey(Store, null=True, on_delete=models.SET_NULL)
phone_line = PhoneNumberField()
phone_line_provider = models.ForeignKey(Provider, null=True, on_delete=models.SET_NULL)
last_verification = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
Pre-Question:
I've allowed Null on the object and left the code to run &
unsurprisingly the objects are created, but phone_line is blank.
I am using the PhoneNumberField library.
I can "mock" this exact code from the shell & the object is created with the correct value every time.
The snippet above is exactly as shown, there is nothing in between the printing of fire_prim & the attempt at creation.
Post-Question:
Changed phone_line to a CharField rather than PhoneNumberField & the phone number is going through just fine. I'm opening an issue on their Github Repo as well.
Explicitly used the string as phone_line when creating the instance.
Verified once more that this can be done from shell without issue.
Input: LifeSafety.objects.create(name='Fire Primary', store=store, phone_line='+16077244546')
Output: LifeSafety: Fire Primary (Indicating QuerySet)
Interestingly when I do use the string explicitly on creation, the object does create with phone_line populated with that string, but I still get the error.
Input:
print('Fire Primary is definitely not Null, here is proof: {}'.format(fire_prim))
fire_primary_obj = LifeSafety.objects.create(
name = 'Fire Primary',
store = store_obj,
phone_line = '+16077244546',
phone_line_provider = an_provider
)
Output is the same stack trace as above (only name differences in diff checker).
I can go into admin and see that it was created, but I still get the NOT NULL constraint exception.

Django deploying on MySQL gives #1071 error "Specified key was too long"

I have been trying this problem for a very long time. But I just cannot seem to find the solution. I am trying to deploy my project on pythonanywhere, where I have chosen MySQL. Whenever I try to migrate my models with python manage.py migrate. I get the following error:
This is my models.
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Thing(models.Model):
thing_name = models.CharField(max_length=64, unique=True)
def __str__(self):
return self.hobby_name
class Person(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
)
first_name = models.CharField(max_length=64, null=True, blank=False)
last_name = models.CharField(max_length=64, null=True, blank=False)
hobbies = models.ManyToManyField(Hobby, blank=False)
email = models.EmailField(max_length=64, blank=True, null=True, unique=True)
city = models.CharField(max_length=64, null=True, blank=False)
zip_code = models.CharField(max_length=10, null=True, blank=False)
description = models.TextField(max_length=2048, null=True, blank=True)
gender = models.CharField(max_length=1,
choices=(
('N', 'No answer'),
('M', 'Male'),
('F', 'Female'),
('O', 'Other')
), null=True, blank=True, default="N"
)
bad = models.BooleanField(default=False)
good = models.BooleanField(default=True)
maximum_hours = models.PositiveIntegerField(default=2)
def __str__(self):
try:
string = self.first_name + " " + self.last_name
except:
string = "name_error"
return string
Last note is that I have DROPPED and re-CREATED the database several times. Each time by:
CREATE DATABASE database_name DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
I am deploying all of this to Pythonanywhere.
The model Thing actually becomes a table. But the model Person does not.
Edit: Here is the full traceback
(hobbyin) 01:16 ~/hobbyin (master)$ python manage.py migrate
System check identified some issues:
WARNINGS:
?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, such as data truncation upon insertion, by escalating warnings into errors. It
is strongly recommended you activate it. See: https://docs.djangoproject.com/en/2.0/ref/databases/#mysql-sql-mode
Operations to perform:
Apply all migrations: account, admin, auth, contenttypes, external_page, sessions, sites, socialaccount
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying account.0001_initial... OK
Applying account.0002_email_max_length... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying external_page.0001_initial...Traceback (most recent call last):
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/utils.py", line 83, in _execute
return self.cursor.execute(sql)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute
return self.cursor.execute(query, args)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 250, in execute
self.errorhandler(self, exc, value)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler
raise errorvalue
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute
res = self._query(query)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 412, in _query
rowcount = self._do_query(q)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 375, in _do_query
db.query(q)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/connections.py", line 276, in query
_mysql.connection.query(self, query)
_mysql_exceptions.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 15, in <module>
execute_from_command_line(sys.argv)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
utility.execute()
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/core/management/__init__.py", line 365, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/core/management/base.py", line 335, in execute
output = self.handle(*args, **options)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 200, in handle
fake_initial=fake_initial,
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration
state = migration.apply(state, schema_editor)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/migrations/migration.py", line 122, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/migrations/operations/models.py", line 92, in database_forwards
schema_editor.create_model(model)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 314, in create_model
self.execute(sql, params or None)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 133, in execute
cursor.execute(sql, params)
File "/home/maxxie/.virtualenvs/hobbyin/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 "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/utils.py", line 83, in _execute
return self.cursor.execute(sql)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute
return self.cursor.execute(query, args)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 250, in execute
self.errorhandler(self, exc, value)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler
raise errorvalue
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute
res = self._query(query)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 412, in _query
rowcount = self._do_query(q)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/cursors.py", line 375, in _do_query
db.query(q)
File "/home/maxxie/.virtualenvs/hobbyin/lib/python3.6/site-packages/MySQLdb/connections.py", line 276, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')
Found the answer. When you deploy your code to production. Make sure that your migration files are removed. Otherwise it might cause unexpected errors such as this one.

Django: Unknown column 'last_login' in 'field list'

I did look through other topics but I couldn't find anything useful or that would help me. All I did was doing python manage.py inspectdb > models.py and then edit the file a bit, the user model and then did migrate.
Now when I try to create a super user I get this error
D:\Programming\Web\blaine county\website>python manage.py createsuperuser --username=andrei --email=andreigames9#gmail.com
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
Password:
Password (again):
Traceback (most recent call last):
File "D:\Programming\Python\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "D:\Programming\Python\lib\site-packages\django\db\backends\mysql\base.py", line 71, in execute
return self.cursor.execute(query, args)
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 250, in execute
self.errorhandler(self, exc, value)
File "D:\Programming\Python\lib\site-packages\MySQLdb\connections.py", line 50, in defaulterrorhandler
raise errorvalue
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 247, in execute
res = self._query(query)
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 411, in _query
rowcount = self._do_query(q)
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 374, in _do_query
db.query(q)
File "D:\Programming\Python\lib\site-packages\MySQLdb\connections.py", line 277, in query
_mysql.connection.query(self, query)
_mysql_exceptions.OperationalError: (1054, "Unknown column 'last_login' in 'field list'")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 15, in <module>
execute_from_command_line(sys.argv)
File "D:\Programming\Python\lib\site-packages\django\core\management\__init__.py", line 371, in execute_from_command_line
utility.execute()
File "D:\Programming\Python\lib\site-packages\django\core\management\__init__.py", line 365, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "D:\Programming\Python\lib\site-packages\django\core\management\base.py", line 288, in run_from_argv
self.execute(*args, **cmd_options)
File "D:\Programming\Python\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 59, in execute
return super().execute(*args, **options)
File "D:\Programming\Python\lib\site-packages\django\core\management\base.py", line 335, in execute
output = self.handle(*args, **options)
File "D:\Programming\Python\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 179, in handle
self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
File "D:\Programming\Python\lib\site-packages\django\contrib\auth\models.py", line 161, in create_superuser
return self._create_user(username, email, password, **extra_fields)
File "D:\Programming\Python\lib\site-packages\django\contrib\auth\models.py", line 144, in _create_user
user.save(using=self._db)
File "D:\Programming\Python\lib\site-packages\django\contrib\auth\base_user.py", line 73, in save
super().save(*args, **kwargs)
File "D:\Programming\Python\lib\site-packages\django\db\models\base.py", line 729, in save
force_update=force_update, update_fields=update_fields)
File "D:\Programming\Python\lib\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 "D:\Programming\Python\lib\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 "D:\Programming\Python\lib\site-packages\django\db\models\base.py", line 880, in _do_insert
using=using, raw=raw)
File "D:\Programming\Python\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "D:\Programming\Python\lib\site-packages\django\db\models\query.py", line 1125, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "D:\Programming\Python\lib\site-packages\django\db\models\sql\compiler.py", line 1280, in execute_sql
cursor.execute(sql, params)
File "D:\Programming\Python\lib\site-packages\django\db\backends\utils.py", line 100, in execute
return super().execute(sql, params)
File "D:\Programming\Python\lib\site-packages\django\db\backends\utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "D:\Programming\Python\lib\site-packages\django\db\backends\utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "D:\Programming\Python\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "D:\Programming\Python\lib\site-packages\django\db\utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "D:\Programming\Python\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "D:\Programming\Python\lib\site-packages\django\db\backends\mysql\base.py", line 71, in execute
return self.cursor.execute(query, args)
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 250, in execute
self.errorhandler(self, exc, value)
File "D:\Programming\Python\lib\site-packages\MySQLdb\connections.py", line 50, in defaulterrorhandler
raise errorvalue
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 247, in execute
res = self._query(query)
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 411, in _query
rowcount = self._do_query(q)
File "D:\Programming\Python\lib\site-packages\MySQLdb\cursors.py", line 374, in _do_query
db.query(q)
File "D:\Programming\Python\lib\site-packages\MySQLdb\connections.py", line 277, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1054, "Unknown column 'last_login' in 'field list'")
This is my models.py https://pastebin.com/5sEY7t5H
The thing is that I had a legacy database and I tried to connect the app to it.
There are a couple of things you need to consider when using user models and legacy databases.
In Django there are four User options built it and what you're trying to do here is not any of them.
First option is to use default User model, second option is to use AbstractUser model, third options is AbstractBaseUser and fourth option is linking back from a related model.
What you are trying to do here is to use AbstractUser option, but this doesn't work like that. AbstractUser options uses all of the field from base User models + additional fields defined in the model.
AbstractBaseUser is bare-bones option and uses three fields from default User model: password, last_login, is_active and whatever other fields you define in the model.
To make it work, you need to run makemigrations and migrate and this will create User model with fields such as last_login plus all of your additional fields. But you cannot do that, because you're using legacy database with managed = False. It means:
If False, no database table creation or deletion operations will be
performed for this model. This is useful if the model represents an
existing table or a database view that has been created by some other
means.
This means that with legacy database and managed = False option, you won't be able to make migrations and migrate, which consequently means that none of the Django options for User models are possible, because you'll always be missing one or another field.
If you're going to use legacy database and your own user model, then you need to dive deep into Django and rewrite (overwrite) at least authentication, login and logout functionalities, because they just won't work with your Users model. You can't just copy database that was created with EntityFramework (I assume) and expect it will work with Django.
You have more or less three sane options:
Ditch Users model from legacy database (you don't have to delete it, just change it from AbstractBase to models.Model) and setup your own in Django and then use legacy database just for storing data.
If you are allowed to do "whatever" with legacy database, switch tables you need to managed = True, delete fields that clash with Django User model in your Users model, make migrations and migrate.
Create new database and copy data from legacy database to new database.

Invalid default value for user_id_id in django

I am new to django and I am creating my models but I am having trouble when trying to add a foreign key to another model. here's my models:
from django.db import models
class User(models.Model):
user_id = models.CharField(max_length=10, primary_key=True)
name = models.CharField(max_length=30)
surname = models.CharField(max_length=30)
role = models.CharField(max_length=10)
address = models.CharField(max_length=50)
email = models.EmailField(max_length=30)
password = models.CharField(max_length=20)
phone = models.IntegerField()
GPA = models.FloatField(max_length=5)
Gender = models.CharField(max_length=1)
def __str__(self):
return self.user_id
class Login(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE, default='00000')
email = models.EmailField(max_length=30)
password = models.CharField(max_length=20)
def __str__(self):
return self.email
When I type makemigrations I get this:
You are trying to change the nullable field 'user_id' on login to non-nullable without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
3) Quit, and let me add a default in models.py
Select an option: 3
So I added a default value but I am getting this error when I tried to migrate. I tried to change user_id from User to AutoField so I don't have to add any default value but it is still giving me this error. Plus I don't know why it says user_id_id at the end. Can anyone help me out with this?
Running migrations:
Rendering model states... DONE
Applying login.0003_login_user_id...Traceback (most recent call last):
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\mysql\base.py", line 112, in execute
return self.cursor.execute(query, args)
File "C:\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 226, in execute
self.errorhandler(self, exc, value)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\connections.py", line 42, in defaulterrorhandler
raise errorvalue
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 223, in execute
res = self._query(query)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 379, in _query
rowcount = self._do_query(q)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 342, in _do_query
db.query(q)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
_mysql_exceptions.OperationalError: (1067, "Invalid default value for 'user_id_id'")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Program Files (x86)\JetBrains\PyCharm 5.0.4\helpers\pycharm\django_manage.py", line 41, in <module>
run_module(manage_file, None, '__main__', True)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\runpy.py", line 182, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "C:/Users/Desktop/Project/TSL/mysite\manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\__init__.py", line 353, in execute_from_command_line
utility.execute()
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\__init__.py", line 345, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\base.py", line 348, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\base.py", line 399, in execute
output = self.handle(*args, **options)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\management\commands\migrate.py", line 200, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\migrations\executor.py", line 92, in migrate
self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_initial)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\migrations\executor.py", line 121, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\migrations\executor.py", line 198, in apply_migration
state = migration.apply(state, schema_editor)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\migrations\migration.py", line 123, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\migrations\operations\fields.py", line 62, in database_forwards
field,
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\mysql\schema.py", line 50, in add_field
super(DatabaseSchemaEditor, self).add_field(model, field)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\base\schema.py", line 396, in add_field
self.execute(sql, params)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\base\schema.py", line 110, in execute
cursor.execute(sql, params)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\utils.py", line 95, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\utils\six.py", line 685, in reraise
raise value.with_traceback(tb)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\db\backends\mysql\base.py", line 112, in execute
return self.cursor.execute(query, args)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 226, in execute
self.errorhandler(self, exc, value)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\connections.py", line 42, in defaulterrorhandler
raise errorvalue
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 223, in execute
res = self._query(query)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 379, in _query
rowcount = self._do_query(q)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\cursors.py", line 342, in _do_query
db.query(q)
File "C:\Users\AppData\Local\Programs\Python\Python35-32\lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1067, "Invalid default value for 'user_id_id'")
Process finished with exit code 1
First of all, as mentioned in the comments, do NOT name the ForeignKey field user_id, but user. This will create a column called user_id in the db table and your model instance's user attribute will return a User instance while its auto-generated attribute user_id will return that user's id.
As for specifying a default value for a ForeignKey. If you do that on the model, make sure you provide an existing User. If you choose to provide a one-off default during makemigrations (if you select option 1), make sure to provide the primary key of an existing User. Alternatively, make sure there are no existing Login records in the db.
django automatically creates a primary keys for all your models, and it manages it internally.
Unless you have a very specific reason, you do not want to be managing or fiddling with the primary key manually.
Now, the specific reason for your error is that once you changed the type of field from CharField to AutoField, it changed the type from a character to an integer - but then you are assigning it a default value of a string (character), which is causing error from your database.
My best advice for you is to start from scratch. You don't need the Login model at all, django comes with authentication built-in and its own "user" model.
from django.db import models
# Renamed from User to MyUser,
# User is a built-in model that comes with django
# and is used when logging people into the system
# https://docs.djangoproject.com/en/1.9/topics/auth/default/
class MyUser(models.Model):
name = models.CharField(max_length=30)
surname = models.CharField(max_length=30)
role = models.CharField(max_length=10)
address = models.CharField(max_length=50)
email = models.EmailField() # email field doesn't need max_length
password = models.CharField(max_length=20)
phone = models.CharField(max_length=30) # this should be a CharField
GPA = models.FloatField()
gender = models.CharField(max_length=1,
choices=(('M', 'Male',),
('F', 'Female',),
('X', 'Prefer not to disclose',)))

Why do I get "table not found" even though I can see it created?

I first created the User model before I read the Django documentation about authentication so I put all attributes in the same model. So, later I tried to split it into User and User profile. But when I run the the population script, it says User profile table is not found even though I saw the SQL that created it.
These are two classes connected to the User model that I import.
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
profilepic = models.ImageField(blank=True)
city = models.ForeignKey(City)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
#property
def avg_rating(self):
return self.userrating_set.all().aggregate(Avg('rating'))['rating__avg']
class UserRating(models.Model):
user = models.ForeignKey(User)
comment = models.CharField(max_length=500)
for_username = models.CharField(max_length=128)
rating = models.IntegerField(default=5)
def __unicode__(self):
return unicode(self.rating)
And this is the portion of the population script where the problem is:
new_user = User.objects.get_or_create(username=username, email=email)[0]
#new_user.profilepic = profile_picture
new_user.firstname = first_name
new_user.secondname = last_name
new_user.save()
new_user_profile = UserProfile.objects.get_or_create(user=new_user, city=created_city)
new_user_profile.slug = username
new_user_profile.save()
And this is the error I get when running the script:
Traceback (most recent call last):
File "C:\Users\bnbih\app_name\populationScript.py", line 108, in <module>
populate()
File "C:\Users\bnbih\app_name\populationScript.py", line 101, in populate
new_user_profile = UserProfile.objects.get_or_create()
File "C:\python27\lib\site-packages\django\db\models\manager.py", line 92, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\python27\lib\site-packages\django\db\models\query.py", line 422, in get_or_create
return self.get(**lookup), False
File "C:\python27\lib\site-packages\django\db\models\query.py", line 351, in get
num = len(clone)
File "C:\python27\lib\site-packages\django\db\models\query.py", line 122, in __len__
self._fetch_all()
File "C:\python27\lib\site-packages\django\db\models\query.py", line 966, in _fetch_all
self._result_cache = list(self.iterator())
File "C:\python27\lib\site-packages\django\db\models\query.py", line 265, in iterator
for row in compiler.results_iter():
File "C:\python27\lib\site-packages\django\db\models\sql\compiler.py", line 700, in results_iter
for rows in self.execute_sql(MULTI):
File "C:\python27\lib\site-packages\django\db\models\sql\compiler.py", line 786, in execute_sql
[Finished in 0.8s with exit code 1]cursor.execute(sql, params)
File "C:\python27\lib\site-packages\django\db\backends\utils.py", line 81, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "C:\python27\lib\site-packages\django\db\backends\utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "C:\python27\lib\site-packages\django\db\utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "C:\python27\lib\site-packages\django\db\backends\utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "C:\python27\lib\site-packages\django\db\backends\sqlite3\base.py", line 485, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: mainapp_userprofile
Django's sqlmigrate just shows you what will get run, it doesn't apply any changes, you need to run migrate
Prints the SQL for the named migration. This requires an active database connection, which it will use to resolve constraint names; this means you must generate the SQL against a copy of the database you wish to later apply it on.

Categories