I'm doing a sqlite3 data migration using South. My old schema has the following model for UserProfile:
class UserProfile(models.Model):
user = models.OneToOneField(User)
weekOne = models.OneToOneField(WeekOne)
weekTwo = models.OneToOneField(WeekTwo)
weekThree = models.OneToOneField(WeekThree)
But I have sense added a number of new weeks, i.e., weekFour, weekFive, weekSix, etc. Every week is itself a model, inheriting from a generic Week model. So the basic prototype of a Week model looks like this:
class WeekOne(Week):
name = u'Week One'
exercises = ['squats', 'lunges', 'stairDaysCount', 'skipStairs']
# Required benchmarks for given exercises
squatBenchmark = 1000
lungeBenchmark = 250
stairDaysCountBenchmark = 3
totalGoals = 4
My question is, what kind of code should I put in my datamigration code so that I can populate old UserProfiles with the additional weeks. I had something like this in mind:
def forwards(self, orm):
for user in orm.UserProfile.objects.all():
user.weekFour = orm.WeekFour()
user.weekFive = orm.weekFive()
# etc.
But that doesn't seem to be working. I get this error when I try to run schema migration:
Migration 'my_app:0002_newWeeks' is marked for no-dry-run
And later this:
DatabaseError: no such column: my_app_userprofile.weekFour_id
Just run this in the terminal
python manage.py schemamigration myapp --auto
Then
python manage.py migrate
Related
Why is the error appearing in django/admin? Migrations ok, I need to have 3 items in the table where I will have results.
class Robot(models.Model):
"""Robot model, speed and position simulation"""
product = models.IntegerField(choices=CHOOSE)
velocity = models.FloatField()
positionX = models.FloatField()
positionY = models.FloatField()
angleTHETA = models.FloatField()
class Meta:`enter code here`
verbose_name = "Robot"
verbose_name_plural = "Robots"
def __str__(self):
resum = self.get_product_display()
return resum
ProgrammingError at /admin/robot/robot/
column robot_robot.velocity does not exist
LINE 1: ...LECT "robot_robot"."id", "robot_robot"."product", "robot_rob...
====
Hello, can someone help me with the above problem, I keep getting this error:
django.db.utils.ProgrammingError: relation "robot_cleanrobot" does not exist
LINE 1: SELECT COUNT(*) AS "__count" FROM "robot_cleanrobot"
first migrations done
then pip install -r requirements.txt
python manage.py startapp
settings
makemigrations & migrate
add model
register a view
nothing helps me, I have done many times from scratch, even deleted the whole directory and also nothing,
I changed the model in the new project and nothing
At the beginning it worked ok for the first time, but when I added the float it all went down - I do not know what to do about it. Please help. Thx.
class CleanRobot(models.Model):
"""..."""
name = models.CharField(max_length=100, null=True, blank=True)
class Meta:
verbose_name = "CleanRobot"
verbose_name_plural = "CleanRobots"
def __str__(self):
return self.name
=================================
Ok, not working: ok step by step what i am doing:
i create a django project
enable (venv)
makemigrations
migrate
pip install -r requirements.txt
copy to settinigs_local project
python manage.py start app
change settings - add code -> reference to local + register application
add code to models
register models
makemigrations
migrate
runserver
dajngo/admin
... +Add is ok, by name entering I get error... I have other projects on my computer and they work normally... I have other projects on my computer and they work normally... not today I have deleted the whole folder for the 20th time...
You are getting the error because the database fields that you requested probably do not exist. Remember to run both makemigrations and migrate commands.
As #ElvinJafarov suggested, migrate the database before proceeding. You get the message about angleTHETA field because of constraints on the database - that’s completely normal. As stated in the message "This is because the database needs something to populate the existing rows".
At this point you can quit and manually define the default value in the models.py (press 2 in message prompt). After this change your Robot by setting a field default, so that Django can populate DB with the default value, e.g.:
angleTHETA = models.FloatField(default=0)
You can also change DB constraints by allowing it to have empty values.
angleTHETA = models.FloatField(null=True, blank=True)
In general, I advise you to read the documentation on migrations.
Update 1:
From your description it seems that first you ran makemigrations and migrate commands, and then created the model. It should be the other way around - first make the model, then run makemigrations. If it went well you should see something like this
and also you should have a new non-empty file in your app's migrations folder. Then run migrate command. You should see something like:
If something went wrong, post the message you did get.
Works:
I don't know which of these things worked but:
i had alpha name and alpha project name so i changed to alphaapp,
after migration 2 I created a new superuser
Maybe this will be useful for someone ;)
I am looking to edit a models.py file for an app, and then migrate the changes to the database (postgreSQL) in the same python code.
In the view definition that is supposed to perform this, I am doing the following:
Open models.py
Append the new table's model to the existing models
Close models.py
Run makemigrations
Run sqlmigrate
Run migrate
It works fine up to Step no.3. The new table's model is being added to models.py, but 'makemigrations' doesn't take in the latest model that was added to models.py.
Effectively, it is not taking the latest copy of models.py for the migrations, it is using the one that existed BEFORE the view was called.
Is there a way to use the latest (appended with the required model) models.py file for the migration commands?
#Here we are attempting to create a user's portfolio table as soon as his registration is complete
#Step1: Adding schema to model.py
modeladdscript = '\n\nclass '+ username + '(models.Model):'
modeladdscript = modeladdscript + '''
stock_id = models.CharField(max_length = 20)
stock_name = models.CharField(max_length = 100)
qty = models.IntegerField(default = 0)
investment = models.FloatField()
hold = models.CharField(max_length = 50)'''
#Step 2: Getting the location of models.py in fileloc
fileloc ='portfolio\models.py' #Need to figure out how to get location of portfolio/models.py
#Step 3: Opening models.py and appending the model add script
with open(fileloc,"a") as f:
f.write(modeladdscript)
#Step 4: Closing models.py
f.close()
#Works absolutely fine till here
# Make migrations
call_command('makemigrations') #This command is not taking the model that has been added above at the time of user creation.
# Remove all the terminal colors, less parsing later.
os.environ['DJANGO_COLORS'] = 'nocolor'
# Capturing the list of applied and unapplied migrations
out = StringIO()
call_command('showmigrations', stdout=out)
# Clean up the line, and remove all applied migrations
work = [line.strip() for line in out.getvalue().split('\n') if not line.startswith(' [X]')]
# Keep looping until we run out of lines.
while work:
app_name = work.pop(0)
while work and work[0].startswith('['):
migration_name = work.pop(0)[4:]
app_path = apps.get_app_config(app_name).module.__file__
# Print the whole path to the migration file that corresponds to this migration
print('--', os.path.abspath(os.path.join(app_path, '../migrations/', '{}.py'.format(migration_name))))
call_command('sqlmigrate', app_name, migration_name[:8])
# Applying all pending migrations
call_command('migrate')
I have a Product model and I want to extend by using OneToOneField.
For example
class Product:
name = models.CharField(..)
price = models.FloatField(...)
I want to do like this
class MyProduct:
product = models.OneToOneField(myapp.Product, on_delete=models.CASCADE)
location = models.CharField(...)
and using signal
def create_myproduct(sender, instance, created, **kwargs):
"""Create MyProduct class for every new Product"""
if created:
MyProduct.objects.create(product=instance)
signals.post_save.connect(create_myproduct, sender=Product, weak=False,
dispatch_uid='models.create_myproduct')
This works for newly created Product, so I can do like this in template.
{{ product.myproduct.location }}
But Old products that created before adding this OneToOneRelation,has no field 'myproduct' and that template code didn't work.
I heard I need a data migrations for old product using RunPython or manage.py shell. Can you teach me how to do? I read a documentation from django, but still don't fully understand.
you can add new migration. and apply it.
something like this code:
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-07-22 06:04
from __future__ import unicode_literals
from django.db import migrations, models
def create_myproducts(apps, schema_editor):
Product = apps.get_model('myapp', 'Product')
MyProduct = apps.get_model('myapp', 'MyProduct')
for prod in Product.objects.all():
MyProduct.objects.create(product=prod)
class Migration(migrations.Migration):
dependencies = [
('myapp', 'your last migration'),
]
operations = [
migrations.RunPython(create_myproducts)
]
I just found out.
Like Rohit Jain said
product.myproduct is None.
When I tried to access product.myproduct, I got an exception that object does not exist. It has a relation to myproduct but the actual object doesn't exist.
What I really want was creating MyProduct object and add it to Product class.
So I did it in python manage.py shell
products = Product.objects.all()
for prod in products:
if not hasattr(prod, 'myproduct'):
prod.myproduct = MyProduct.objects.create(product=prod)
prod.save()
I think it works for me now.
Thank you guys
You should just migrate your models in a normal way
python manage.py makemigrations
python manage.py migrate
During making migrations you will be asked how to fill new fields for existing data
Please notice that when you are using Django under 1.7 version you do not have migrations (and syncdb will not do the job for existing tables) - consider using the 3rd part tool like south
Following is my model:
class myUser_Group(models.Model):
name = models.CharField(max_length=100)
class Channel(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
belongs_to_group = models.ManyToManyField(myUser_Group)
class Video(models.Model):
video_url = models.URLField(max_length=300)
belongs_to_channel = models.ManyToManyField(Channel)
description = models.CharField(max_length=1000)
tags = TagField()
class UserProfile(models.Model):
user = models.OneToOneField(User)
class User_History(models.Model):
date_time = models.DateTimeField()
user = models.ForeignKey(UserProfile, null=True, blank=True)
videos_watched = models.ManyToManyField(Video)
I just wanted to remove the underscores from all the class names so that User_History looks UserHistory, also the foreign keys should be updated. I tried using south but could not find it in the documentaion.
One way is export the data, uninstall south, delete migration, rename the table and then import data again. Is there any other way to do it?
You can do this using just South.
For this example I have an app called usergroups with the following model:
class myUser_Group(models.Model):
name = models.CharField(max_length=100)
which I assume is already under migration control with South.
Make the model name change:
class MyUserGroup(models.Model):
name = models.CharField(max_length=100)
and create an empty migration from south
$ python manage.py schemamigration usergroups model_name_change --empty
This will create a skeleton migration file for you to specify what happens. If we edit it so it looks like this (this file will be in the app_name/migrations/ folder -- usergroups/migrations/ in this case):
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Change the table name from the old model name to the new model name
# ADD THIS LINE (using the correct table names)
db.rename_table('usergroups_myuser_group', 'usergroups_myusergroup')
def backwards(self, orm):
# Provide a way to do the migration backwards by renaming the other way
# ADD THIS LINE (using the correct table names)
db.rename_table('usergroups_myusergroup', 'usergroups_myuser_group')
models = {
'usergroups.myusergroup': {
'Meta': {'object_name': 'MyUserGroup'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['usergroups']
In the forwards method we are renaming the database table name to match what the django ORM will look for with the new model name. We reverse the change in backwards to ensure the migration can be stepped back if required.
Run the migration with no need to import/export the exisiting data:
$ python manage.py migrate
The only step remaining is to update the foreign key and many-to-many columns in the models that refer to myUser_Group and change to refer to MyUserGroup.
mmcnickle's solution may work and seems reasonable but I prefer a two step process. In the first step you change the table name.
In your model make sure you have your new table name in:
class Meta:
db_table = new_table_name'
Then like mmcnickle suggested, create a custom migration:
python manage.py schemamigration xyz migration_name --empty
You can read more about that here:
https://docs.djangoproject.com/en/dev/ref/models/options/
Now with your custom migration also add the line to rename your table forward and backwards:
db.rename_table("old_table_name","new_table_name")
This can be enough to migrate and change the table name but if you have been using the Class Meta custom table name before then you'll have to do a bit more. So I would say as a rule, just to be safe do a search in your migration file for "old_table_name" and change any entries you find to the new table name. For example, if you were previously using the Class Meta custom table name, you will likely see:
'Meta': {'object_name': 'ModelNameYouWillChangeNext', 'db_table': "u'old_table_name'"},
So you'll need to change that old table name to the new one.
Now you can migrate with:
python manage.py migrate xyz
At this point your app should run since all you have done is change the table name and tell Django to look for the new table name.
The second step is to change your model name. The difficulty of this really depends on your app but basically you just need to change all the code that references the old model name to code that references the new model name. You also probably need to change some file names and directory names if you have used your old model name in them for organization purposes.
After you do this your app should run fine. At this point your task is pretty much accomplished and your app should run fine with a new model name and new table name. The only problem you will run into using South is the next time you create a migration using it's auto detection feature it will try to drop the old table and create a new one from scratch because it has detected your new model name. To fix this you need to create another custom migration:
python manage.py schemamigration xyz tell_south_we_changed_the_model_name_for_old_model_name --empty
The nice thing is here you do nothing since you have already changed your model name so South picks this up. Just migrate with "pass" in the migrate forwards and backwards:
python manage.py migrate xyz
Nothing is done and South now realizes it is up to date. Try:
python manage.py schemamigration xyz --auto
and you should see it detects nothing has changed
I would like to change a name of specific fields in a model:
class Foo(models.Model):
name = models.CharField()
rel = models.ForeignKey(Bar)
should change to:
class Foo(models.Model):
full_name = models.CharField()
odd_relation = models.ForeignKey(Bar)
What's the easiest way to do this using South?
You can use the db.rename_column function.
class Migration:
def forwards(self, orm):
# Rename 'name' field to 'full_name'
db.rename_column('app_foo', 'name', 'full_name')
def backwards(self, orm):
# Rename 'full_name' field to 'name'
db.rename_column('app_foo', 'full_name', 'name')
The first argument of db.rename_column is the table name, so it's important to remember how Django creates table names:
Django automatically derives the name of the database table from the name of your model class and the app that contains it. A model's database table name is constructed by joining the model's "app label" -- the name you used in manage.py startapp -- to the model's class name, with an underscore between them.
In the case where you have a multi-worded, camel-cased model name, such as ProjectItem, the table name will be app_projectitem (i.e., an underscore will not be inserted between project and item even though they are camel-cased).
Here's what I do:
Make the column name change in your model (in this example it would be myapp/models.py)
Run ./manage.py schemamigration myapp renaming_column_x --auto
Note renaming_column_x can be anything you like, it's just a way of giving a descriptive name to the migration file.
This will generate you a file called myapp/migrations/000x_renaming_column_x.py which will delete your old column and add a new column.
Modify the code in this file to change the migration behaviour to a simple rename:
class Migration(SchemaMigration):
def forwards(self, orm):
# Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')
def backwards(self, orm):
# Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')
I didn't know about db.rename column, sounds handy, however in the past I have added the new column as one schemamigration, then created a datamigration to move values into the new field, then a second schemamigration to remove the old column
Django 1.7 introduced Migrations so now you don't even need to install extra package to manage your migrations.
To rename your model you need to create empty migration first:
$ manage.py makemigrations <app_name> --empty
Then you need to edit your migration's code like this:
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('yourapp', 'XXXX_your_previous_migration'),
]
operations = [
migrations.RenameField(
model_name='Foo',
old_name='name',
new_name='full_name'
),
migrations.RenameField(
model_name='Foo',
old_name='rel',
new_name='odd_relation'
),
]
And after that you need to run:
$ manage.py migrate <app_name>
Just change the model and run makemigrations in 1.9
Django automatically detects that you've deleted and created a single field, and asks:
Did you rename model.old to model.new (a IntegerField)? [y/N]
Say yes, and the right migration gets created. Magic.
Add south to your installed apps in project setting file.
Comment out the added/modified field/table.
$ manage.py Schemamigration <app_name> --initial
$ manage.py migrate <app_name> --Fake
Un-comment the field and write the modified one
$ manage.py Schemamigration --auto
$ manage.py migrate <app_name>
If you are using 'pycharm', then you can use 'ctrl+shift+r' instead of 'manage.py' , and 'shift ' for parameters.