I have no idea what Django is trying to tell me. I have a model, WeekTwo, which inherits from Week, which inherits from modelsModel. I have another model, UserProfile. I want to use WeekTwo as a OneToOne Key in UserProfile, so I inserted the following line of code:
weekTwo = models.OneToOneField(WeekTwo)
However, when I try to migrate my database using python manage.py schemamigration my_app --auto, I get the following error:
The field 'UserProfile.weekTwo' does not have a default specified, yet is NOT NULL.
I tried adding default=0 to my weekTwo declaration, but now I'm getting this error when I try the schema migration:
IntegrityError: column weekTwo_id is not unique
Moreover, south is now telling me that I am in an interim state between migrations and that I might be able to recover. I literally have no idea what any of this means.
Be aware before going further, be sure that if South already did any migration that has been failed, It's better to redo|recover to the last migration that was working.
You have two options here, at first you can do Data Migration. Look at ref also.
In Second way You can make weekTwo field null and blank first
weekTwo = models.OneToOneField(WeekTwo, null=True, blank=True)
Then let South generate a migration for you by
python manage.py schemamigration my_app --auto
I'm sure South won't complain about it now, Then
python manage.py migrate
If everything is okay now, You can now get back and change to weekTwo field to
weekTwo = models.OneToOneField(WeekTwo)
And generate migration then migrate them.
Anyway, When south find out your field in not NULL and doesn't have a default value, at the schemamigration step it will suggest you to provide a value for it, Again here your field is OneToOneField, because even south gives you chance to provide a default value for your existed record on model again uniqueness of weekTwo field will raise an error.
I think still you have to go with Data Migration if second way didn't work, Or gives it a shot and try the second way this time instead of make it null, blank change the whole Field type. Try it with;
weekTwo = models.ForeignKey(WeekTwo)
But keep in mind Data migration would be definitely smarter and standard way here.
Related
I am new to django and I am facing some problem.
This was my previous model.
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
I added some data to this model.
After that I added one more field to it.
Now my model looks like this..
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
age = models.IntegerField()
When I ran the command python manage.py makemigrations I got the following error which is obvious.
You are trying to add a non-nullable field 'age' to blog 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 with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option:
I don't want to add default so I deleted the table contents by accessing db.sqlite3
But again after running python manage.py makemigrations I am getting the same error.why?
Even though you have deleted the table, any changes to your Django model will always refer to the previous migration of that model, hence it still requires you to set a default value. If you're still in development, then you could delete the migrations for that model and then makemigrations again. But, this is terrible practice and you should never do this unless you are consciously squashing your models, the better way is to do what Django is telling you and set a default. This'll help in the long run anyways with error handling.
The other answers address how to set defaults quite well.
When you add a new field (i.e., column) to a database table, that field applies to all rows in the table...the existing ones and any new ones. If the field cannot be null, then some value must be specified for all of the existing rows.
By default, IntegerField() is non-nullable. This explains why you are getting the warning. You have a few options:
You can choose a default "one-off" initial value like Django suggests. All existing rows will use this value for the new field.
Assign your own values to each existing row for the new field.
Use the blank and null arguments in your model field to allow the field to accept null values.
For the last option, you'd do this like so:
models.IntegerField(blank=True, null=True)
But that might not be the best choice depending on your use case. If nullable values don't make sense for your field, I would avoid making the field support nulls.
age = models.IntegerField(null=True)
Django models fields are null set to true by default.
The way you can solve this:
Delete the Blog table from the database.
Delete the migrations folder from the app that contains Blog model.
Remove all data from django_migrations table.
Now run makemigrations and then migrate command.
Hope this will solve your problem.
Do what Django is telling you, then you can remove the default attribute if you don't need it. But it's a good practice to keep it anyway
I'm working with an existing SQL database in Django. These tables for some reason were never given primary keys so I'm just going through and assigning them ones. In one of these models, I changed an existing unique index to a primary index using primary_key = True. I then ran ./manage.py makemigrations (app_name); ./manage.py migrate. I came across this error: (1091, "Can't DROP 'id'; check that column/key exists"). It seems as though Django assumed that there was an id field for the model when there wasn't because I was able to use phpMyAdmin to make an id field, and when I re-ran the migration it succeeded. While I was able to fix my problem I doubt that this is the best way to go about it. What is the correct way to deal with this problem?
You could fake a migration only including removing the "id" field using the --fake option when migrating, so django thinks that it had deleted the id field when really it never existed.
The problem is pretty self-explanatory in the title. Do I need to do that or I just need to edit the existing migration file?
Yes, Django won't recognize the field if you change the name. I will say that the "field does not exist", so YES, you have to run Django's South migrate / schemamigration as you asked.
Datatype YES as well. Django may be okay at first if you only change the field type depending, but may run into problems later depending on what you have in that field.
You need to do a schemamigration every time you change your models.
On every call of python manage.py migrate command south record number of the latest migration applied into database migrationhistory table. So if you just change existing migration it won't be applied because south would think it's already applied.
You can make a backward migration, fix next migration, even delete it and make a new one and only then migrate forward.
I'm trying to update a field key from the following in the model:
name = models.CharField(max_length=255, unique = True)
to:
name = models.CharField(max_length=255, unique = False)
However I need to update the mysql db without losing any of the current data. How would I go about doing this? I tried $ python manage.py syncdb but it doesn't seem to update the key.
That is because syncdb doesn't do that. It only creates new tables, but doesn't change the existing if your model changes.
On a dev environment, to update your database after changing your model, you can use python manage.py reset appname to empty out your database, and use syncdb again.
Otherwise, you have to use tools such as South. South was made to handle migrations, but also changing the database when the model changes.
There is also django-evolutions that does just what you want, but I still recommend South as its migrations features are almost always going to be of some use.
You could use PHPMyAdmin and remove the unique index from this field.
Regarding Django & Python:
The Error:
Exception Type: DatabaseError
Exception Value:
column objects_thing.name_id does not exist
LINE 1: ...s_thing"."created", "objects_thing"."modified", "objects...
In my manage.py sql objects
CREATE TABLE "objects_thing" (
otherstuff,
otherstuff,
"name_id" integer NOT NULL REFERENCES "profiles_name" ("id"),
otherstuff,
);
So it clearly exists.
I've ran syncdb.
Why am I getting this error? And how do I go about fixing it? (I'm a newbie to all of this) Thank you in advance for the help.
EDIT:
Thing Model:
class Thing(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
name = models.ForeignKey(Name)#The name for this thing
current_allocation = models.DecimalField(max_digits=13, decimal_places=2, null=True, blank=True)
target_allocation = models.DecimalField(max_digits=13, decimal_places=2, null=True, blank=True)
placeholder = models.ForeignKey(Entity, null=True, blank=True, on_delete=models.SET_NULL)
avatar = models.ImageField(upload_to='avatars/thing/', null=True, blank=True)
syncdb doesn't change existing tables in your database, so if you run that, and then change your model, your model is now out of sync with the table it represents. Running syncdb again will not fix that.
You either need to use something like south to do a migration, delete the table from your DB so that syncdb will recreate it, or manually run an ALTER TABLE on your DB.
EDIT (greater detail)
When you create a subclass of Model in models.py, it acts as a representation of a database table, but doesn't automatically have a database table. You get that by running python manage.py syncdb. Django, then, looks through all your models.py files, generates the SQL required to actually create a table like that and then runs it on your database. The end result is that you end up with actual database tables that are tied to your models.
However, syncdb only creates tables. It does not alter them. So, if you go and change one of your models (add a field, change the name of a field, etc.), nothing has happened at the database level. Running syncdb again will not help, either, because there's no new tables to create. You have to somehow get the table to match the model and vice versa, though, so that's where your options come in:
Use South (link above). South enables you to create migrations, so when you change something on your models you can run:
python manage.py schemamigration --auto yourapp
And it will generate code that will alter the table to match your model. You then need only apply the migration with:
python manage.py migrate yourapp
And you're done. The table now matches your model and all is right in the world again.
You can manually delete the table from your database. You wouldn't want to do this in production because all the data in that table will go along with it, but in development it shouldn't be a problem. After the table is gone, you can then run:
python manage.py syncdb
Because, the table no longer exists, Django will create it, but it will create it based on your current model's state. The net result is the same, your model and table match, so you're good to go.
You can manually alter the table. This requires that you figure out what SQL needs to be applied to change the table to match your model. You run this SQL on your database, and then the table is in parity with the model.
The point is that somehow, someway, you must update the table to reflect any changes you make to your models. The model isn't the table, it's just a programmatic representation of it.
The column might not necesarrily exist. The sql command just shows the sql used to create it, It is based on your current model. You could delete the table and re syncdb or manually add the column. https://docs.djangoproject.com/en/dev/ref/django-admin/#sql-appname-appname
I think there is a little confusion regarding the django Model and the actual database table
The django model is just some python code. It is a python object that is connected to a sql table. The database backend is specified in settings.py. The database contains the actual table. The error you are encountering is indicating that the python model is not the same as the actual database table.