I use Django 1.10
school/models.py
class School(models.Model):
name = models.CharField(max_length=10,null=False)
school_id = models.CharField(max_length=8,null=False)
weather = models.ForeignKey(Weather,related_name="school")
When I modified the school class by adding eng_name = models.CharField(max_length=50,null=False)
I deleted the migrations file first.
And after running the command:
python manage.py makemigrations school
python manage.py migrate --fake-initial school
python manage.py migrate school
The messages both for the migrate are
Operations to perform:
Apply all migrations: school
Running migrations:
No migrations to apply.
But the database didn't update.
What is the possible reason to cause this issue?
UPDATAE
migrations/0001_initial.py
class Migration(migrations.Migration):
initial = True
dependencies = [
('weather', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='School',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=10)),
('eng_name', models.CharField(max_length=50)),
('school_id', models.CharField(max_length=8)),
('weather', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='school', to='weather.Weather')),
],
),
]
python manage.py showmigrations --plan
[X] weather.0001_initial
[X] school.0001_initial
These both are the latest migrate .
Django is storing applied migrations in database as table (django_migrations) with columns (id, app, name, applied). Just remove row with applied initial migration for "school" app then make migrate. And, in future, do not remove old transactions files. With them django will create properly named transactions for migration-mechanism.
Related
As a proof of concept, I made these two migrations in the simplest possible Django app, polls.
Here is migration 0001.
# Generated by Django 4.0.5 on 2022-06-15 18:17
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Question',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question_text', models.CharField(max_length=200)),
],
),
]
Here is migration 0002
# Generated by Django 4.0.5 on 2022-06-15 18:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('polls', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='question',
name='question_type',
field=models.CharField(max_length=200, null=True),
),
]
And here is the model.
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
question_type = models.CharField(max_length=200, null=True)
Let's say I've migrated the database, and now want to revert 0002. I run the following command python manage.py sqlmigrate polls 0002 --backwards and get this SQL
BEGIN;
--
-- Add field question_type to question
--
CREATE TABLE "new__polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL);
INSERT INTO "new__polls_question" ("id", "question_text") SELECT "id", "question_text" FROM "polls_question";
DROP TABLE "polls_question";
ALTER TABLE "new__polls_question" RENAME TO "polls_question";
COMMIT;
Clearly, it's dropping the entire column (by dropping and recreating the table), but I'm curious, could Django be made to keep that column without deleting it?
Error Message
django.db.utils.OperationalError: no such table: clientauth_tbltokentypes
What I am trying to do
I am trying to migrate data with table generation.
models.py
class tbltokentypes(models.Model):
token_type_id: AutoField(primary_key=True)
token_type: CharField(max_length=30)
I ran the command python manage.py makemigrations, which created the file 0001_initial.py.
Then in the migration file, I added managers:
from django.db import migrations, models
from clientauth.models import tbltokentypes
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='tbltokentypes',
fields=[
('token_type_id', models.AutoField(primary_key=True, serialize=False, verbose_name='token_type_id')),
('token_type', models.CharField(max_length=30)),
],
managers=[
tbltokentypes(token_type = "Registration").save()
]
)
]
Am I missing anything?
Wrap your function call in migrations.RunPython, otherwise it will be run while assigning operations, before the migration can even be run to create your table.
from django.db import migrations, models
# from clientauth.models import tbltokentypes # Remove this
# Add this function
def migrate_tbltokentypes(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
tbltokentypes = apps.get_model('clientauth', 'tbltokentypes')
tbltokentypes(token_type="Registration").save()
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='tbltokentypes',
fields=[
('token_type_id', models.AutoField(primary_key=True, serialize=False)),
('token_type', models.CharField(max_length=30)),
],
# managers=[ # Change this
# tbltokentypes(token_type = "Registration").save() #
# ] #
),
migrations.RunPython(migrate_tbltokentypes), # to this
]
Also note, from https://docs.djangoproject.com/en/3.2/topics/migrations/#data-migrations:
[Data migrations are] best written as separate migrations, sitting alongside your schema migrations.
python manage.py makemigrations --empty clientauth --name migrate_tbltokentypes
Unique Class or extend Class or Subclass in Python Django?
In the following situation, I have a feeling I need to ?extend? the Migration class instead of re-stating it in the second module. Or is a child class needed?
A goal here: To create a postgres table called venues. There is already a models/venues.py that seems to be set up ok.
migrations/0001_initial.py:
class Migration(migrations.Migration):
initial = True
dependencies = [('auth', '0012_alter_user_first_name_max_length'),]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, ...)),
('password', models.CharField(max_length=128, ...)),
...
migrations/0002_venue.py:
class Migration(migrations.Migration):
dependencies = [('app', '0001_initial'),]
operations = [
migrations.CreateModel(
name='Venue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True...)),
('name', models.CharField(blank=True ...)),
('address', models.CharField(blank=True...)),
...
** models/venue.py:**
class Venue(models.Model):
name = models.CharField(blank=True, null=True...)
address = models.CharField(blank=True, null=True...)
city = models.CharField(blank=True, null=True, ...)
zip = models.CharField(blank=True, null=True...)
#gps_coords = models.CharField(blank=True...)
gps_lat = models.DecimalField(max_digits=14...)
gps_long = models.DecimalField(max_digits=14...)
description = models.TextField(blank=True, ...)
website = models.URLField(blank=True...)
contact_phone = models.CharField(blank=True...)
contact_email = models.EmailField(blank=True...)
contact_name = models.CharField(blank=True...)
def __str__(self):
return self.name + " " + self.description
Help?
Once you create your model class, you need to run python manage.py makemigrations and django will create a migration file. (Make sure you've added the app to the INSTALLED_APPS on project's settings.py
Once you run the makemigrations, you'll be able to see the migration file in your app's migrations folder. Having this file doesn't mean the table is created. It just represents the set of instructions that'll run on database when you run the migrate command.
When you have the new migration file, you can run python manage.py migrate, and that migration file will be applied to your database.
You can run the showmigrations command to see which migrations are applied on your database.
python manage.py showmigrations
or
python manage.py showmigrations app_name
I'm looking to use the PostgreSQL-specific ArrayField in my Django project, but it doesn't show up in the migrations after I run makemigrations. Any ideas why?
Django v2.1
Postgresql v9.6.6
# Models.py
from django.db import models
from django.contrib.postgres.fields import ArrayField
class MyClassName(models.Model):
udi = ArrayField(models.CharField()),
version = models.IntegerField()
Then I run: python3 manage.py makemigrations
# 0001_initial.py
migrations.CreateModel(
name='MyClassName',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('version', models.IntegerField()),
],
),
As you can see, the field 'udi' is suspiciously missing.
The problems are a comma at the end of the ArrayField() and CharField would need max_length too.
class MyClassName(models.Model):
udi = ArrayField(models.CharField(max_length=10))
version = models.IntegerField()
Run makemigrations again and you will get a migration you want.
I recently checked out the master branch of a project, and there were model changes not yet reflected in a migration:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auditlog, auth, contenttypes, lucy_web, oauth2_provider, otp_static, otp_totp, sessions, two_factor
Running migrations:
No migrations to apply.
Your models have changes that are not yet reflected in a migration, and so won't be applied.
Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
Following the instructions, I ran makemigrations to create them:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py makemigrations
Migrations for 'auth':
venv/lib/python3.6/site-packages/django/contrib/auth/migrations/0009_auto_20180425_1129.py
- Alter field email on user
Migrations for 'lucy_web':
lucy_web/migrations/0146_auto_20180425_1129.py
- Alter field description on sessiontype
- Alter field short_description on sessiontype
Interestingly, the 0009_auto_20180425_1129.py migration was created in the venv containing Django's source code (version 1.11.9), which I don't believe anyone on our team changed. Here is this migration:
# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2018-04-25 18:29
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('auth', '0008_alter_user_username_max_length'),
]
operations = [
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(blank=True, max_length=254, unique=True, verbose_name='email address'),
),
]
It seems 'innocent enough', but when I try to migrate, I get the following ProgrammingError:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auditlog, auth, contenttypes, lucy_web, oauth2_provider, otp_static, otp_totp, sessions, two_factor
Running migrations:
Applying auth.0009_auto_20180425_1129...Traceback (most recent call last):
File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "auth_user_email_1c89df09_uniq" already exists
Some of the answers at django.db.utils.ProgrammingError: relation already exists seem to be pretty drastic, like deleting all migrations or using the command option --fake, without providing an explanation of what fundamentally is causing the error.
Any idea how to address this error?
It turns out that the auth_user_email_1c89df09_uniq relation is actually a Constraint (so not data). I managed to migrate by simply dropping/deleting this constraint in pgAdmin, and similarly for the auth_user_email_1c89df09_like index (for which a ProgrammingError popped up after that).
After this, I was able to migrate:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auditlog, auth, contenttypes, lucy_web, oauth2_provider, otp_static, otp_totp, sessions, two_factor
Running migrations:
Applying auth.0009_auto_20180425_1129... OK
Applying lucy_web.0146_auto_20180425_1129... OK
and the constraint and index have been put back into the auth_user table:
In my case, the culprit was
User._meta.get_field("email")._unique = True
somewhere in the .py files.
After deleting the line, makemigrations stopped creating migration file in auth folder, while keeping the uniq constraint that was created by that line.
Try this, this will work:
NOTE: All data in this field will be lost
After running the last migrations, you have this file 0009_auto_20180425_1129.py
which is waiting for a migrate... If you have not this file anymore, re run makemigrations to have one last migration file waiting for migrate.
Go trough that file, in your case 0009_auto_20180425_1129.py, and inside
operations
I suppose you don't have any data in db
add these lines:
migrations.RemoveField(
model_name='user',
name='email',
),
migrations.AddField(
model_name='user',
name='email',
field=models.EmailField(blank=True, max_length=254, unique=True, verbose_name='email address'
),
feel free to comment what you get after
After searching for several solutions, I have found one without data loss based on Lemayzeur's suggestion:
STORED_DATA = {}
def store_data(apps, schema_editor):
User = apps.get_model('users', 'User')
for user in User.objects.all():
STORED_DATA[user.id] = user.email
def restore_data(apps, schema_editor):
User = apps.get_model('users', 'User')
for key, value in STORED_DATA.items():
user = User.objects.get(id=key)
user.email = value
user.save()
class Migration(migrations.Migration):
dependencies = [
...
]
operations = [
migrations.RunPython(store_data, restore_data),
migrations.RemoveField(
model_name='user',
name='email',
),
migrations.AddField(
model_name='user',
name='email',
field=models.EmailField(
blank=True,
max_length=254,
unique=True,
verbose_name='email address',
)
),
migrations.RunPython(restore_data, store_data),
]