Django asking for default value during migration - python

I've got the following models:
title = models.CharField(max_length=100)
description = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Ingredient(models.Model):
ingredients_recipe = models.ForeignKey(Post, on_delete=models.CASCADE)
type = models.CharField(max_length=50)
quantity = models.IntegerField()
measurement = models.CharField(max_length=50)
class MethodStep(models.Model):
methods_recipe = models.ForeignKey(Post, on_delete=models.CASCADE, null=True)
step = models.TextField()
When i try to run makemigrations, i get no errors for the Ingredient class, but on the MethodStep class i get an error saying:
You are trying to add a non-nullable field 'methods_recipe' to methodstep without a default; we can't do that (the database needs something to populate existing rows).
Can someone help me? I'm not sure whats different about each of these classes which would mean the MethodStep has an error but Ingredient doesn't.
Edit: I've also tried deleting/clearing/removing the db but the error persists everytime makemigrations is run.

Sometimes in addition to resetting the database you will also have to remove all existing Migrations from your project (or at least the ones for the package these models belong to).
Delete all files in the migrations folder EXCEPT for the _init__.py file.
When simply dumping your db and restarting django, startup will apply the migration history in the order they were created.
That means if you added this ForeignKey Field after already migrating changes to the db, django won't let you migrate without a default unless you delete the migration history.

This happens after you create a model field.
This is because you have added rows/objects in the table/model since your last migration.
Django is aware of table rows in your db and and cannot figure out what to fill the new field with for the old rows. To fix this, depending on the type of field you created newly, update the field adding:
default=None :if you don't mind those fields having nothing to go with otherwise consider some default string or int or float consistent with the field going forward
AND also add
blank = True
To take everything back to square one, apart from deleting your db, you will also need to delete associated migration files. If you are not sure which it is, delete all of them but do not touch the init file in the folder. Then makemigrations and migrate.
PS: I'm sure you know that with the last approach you lose all records in the model.

Related

Django AutoSlugField not considering soft deleted instances by Django Safe Delete

In our model we have a name and slug fields. This is how it looks like:
class MyModel(CommonInfo, SafeDeleteModel):
name = models.CharField(_('Name'), max_length=255, null=True, blank=True)
slug = AutoSlugField(_('Url'), populate_from='name', unique=True,)
For the slug field we generate an unique slug every time our model is saved.
We are also using Django Safe Delete library to soft delete our model:
Django Safe Delete
Django Autoslug
That means that for example if we create a new instance of our model with Name "My Model" it will auto generate a slug that will look like this: "/my-model".
Now let's say we "soft delete" this instance with the slug "/my-model". In our database there will be a property deleted which contains the date when the model was deleted. We don't show this one in our application, it is completely ignored (because it is soft deleted, that's fine).
The problem is that next time we create another one with the same name "My Model" it will auto generate the slug "/my-model" again, not considering that there is already one (which is soft deleted) with the same name and slug. We would need something like "/my-model-1" or whatever that is unique.
We are missing the connection between the autoslug and the safe-delete libraries, somehow the autoslug needs to know that there might be soft deleted ones and consider them when generating the unique slug.
Any help would be really appreciated and please consider that we are totally new in Django / Python.
if this doesn't work, our workaround will be generating the slug using 2 fields (name & id). It will generate a slug that will look like this: "/my-model/12345" and will be always unique since id is unique.
I think we found it.
We needed to create a new Manager that can see all the instances, even the soft deleted ones:
class MyModelAllManager(SafeDeleteManager):
_safedelete_visibility = DELETED_VISIBLE
Then in our model we pass it to the AutoSlugField function:
class MyModel(CommonInfo, SafeDeleteModel):
# We don't know why but it only works if we create a variable and assign the Manager to it. It doesn't work if we pass the Manager directly to the AutoSlugField function.
all_objects = MyModelAllManager()
name = models.CharField(_('Name'), max_length=255, null=True, blank=True)
slug = AutoSlugField(_('Url'), populate_from='name', unique=True, manager=all_objects)
That does the magic.

Django Migrate Fails due to Type Conflict

Here is my Chapter model code:
class Chapter(models.Model):
name = models.CharField(max_length=180)
is_canon = models.BooleanField(default=True)
series_id = models.ForeignKey('Series', on_delete=models.CASCADE,
blank=True, null=True)
def __str__(self):
return self.name
When running python3 manage.py makemigrations, I provided a one off value of 'NULL' for the new field series_id in order to populate existing rows, when I should have backed out and added blank=True, null=True to the definition, as it is now in the code provided above. So, now, I want to run python3 manage.py migrate, but of course the migration fails because I've got a bunch of 'NULL' strings in places where django is expecting actual NULL values/integer values.
How to I get rid of those 'NULL' values and reset things so I can migrate?
Thank you for your time.
Adding to Pythonista comment. You could roll back to the previous migration. Delete the migration file and create it once again. That is the cleanest way in my opinion.

Django on_delete=models.CASCADE has no effect at SQL level

My models.py file contains:
class User(models.Model):
email = models.CharField(max_length=100, unique=True)
password = models.CharField(max_length=100)
create_time = models.DateTimeField(auto_now_add=True)
class Session(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
token = models.CharField(max_length=100, unique=True)
When i command python manage.py makemigrations and then command python manage.py sqlmigrate <app_name> <migration_name> i don't see anything that says "ON DELETE=CASCADE"
However, the migrations work without failure when i type python manage.py migrate.
Now, if i go to the mysql table (using SequelPro) and try to delete a row for a user who currently has a session entry, i get the following error: "One row was not removed. Reload the table to be sure that the contents have not changed in the meantime. Check the Console for possible errors inside the primary key(s) of this table!".
Now, when i go to the session table and delete the sessions of this user and then try to delete the user's row from the user table, it deletes properly. This indicates ON DELETE = CASCADE is not actually working at the MySQL level.
How can i correct it?
From the docs (emphasis mine):
ForeignKey.on_delete
When an object referenced by a ForeignKey is deleted, Django will
emulate the behavior of the SQL constraint specified by the on_delete
argument.
Django does not actually set an ON DELETE clause in the database. If you need one, you can add one manually using a RunSQL operation. Be sure to use the same index name, or keep the original index, or you might run into errors later on.

django: default for non-nullable field

I am learning django by doing some tutorials and am currently on ownership in the effective-django tutorial. Unfortunately, the tutorials is written for an older version of django so some things are slightly different.
I am running into problems when adding an 'owner' field to my model Contact in models.py:
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
class Contact(models.Model):
"""
Interface for contact class
"""
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
owner = models.ForeignKey(User)
def __str__(self):
return ' '.join([self.first_name, self.last_name])
def get_absolute_url(self):
return reverse('contacts-view', kwargs={'pk': self.id})
When trying to run 'makemigrations', i get warnings:
You are trying to add a non-nullable field 'owner' to contact without a default: can't do that
This makes sense for an existing database, so i tried flushing the database. However, the problem remains. What should be the default value for the field owner? I also tried making the field nullable but that gives me the error that field owner cannot be null.
I usually set to 1. In this case already existed records will be assigned to the first user.
If you want you can later reassign these records in the next data migration.
Well, it does not matter if the database is empty or not. It matters that you probably have already at least one migration that first creates the model, and then you try to run makemigrations that adds the field.
If these migrations are not too important for you (which I recon they are not since this is a tutorial), just delete all previous migrations and run makemigrations fresh.
Alternatively, you would have to manually change migrations, possibly provide a default value etc.

south migration: "database backend does not accept 0 as a value for AutoField" (mysql)

I'm new to django and trying to have a Foreign key back to users for an assignee and reporter.
But when i'm trying to apply the change with South i get the error
ValueError: The database backend does not accept 0 as a value for AutoField.
My Model Code:
class Ticket(models.Model):
title = models.CharField(max_length=80)
text = models.TextField(blank=True)
prioritys = models.ForeignKey(Prioritys)
ticket_created = models.DateTimeField(auto_now_add=True)
ticket_updated = models.DateTimeField(auto_now=True)
assignee = models.ForeignKey(User, null=True, related_name='assignee')
reporter = models.ForeignKey(User, null=True, related_name='reporter')
def escaped_text(self):
return markdown.markdown(self.text)
def __unicode__(self):
return self.text
If this happens when you run manage.py migrate (or manage.py syncdb in old versions), the reason maybe is that you have tried to add a foreign key to a model which uses AutoField as its primary key, and use 0 as the default value. Edit the migration file and remove the argument default=0 in AddField operations. It works for me in Django 1.10.
I wasn't using South, but I recently upgraded from Django 1.4 to 1.6 (with MySQL as db backend for both), and was getting the same ValueError when trying to save some models. I tracked it down to a field that was a recursive ForeignKey. So I had:
class Foo(models.Model):
...
duplicate = models.ForeignKey('self', blank=True, null=True)
...
Somewhere along the line—unfortunately I'm not sure where—many of my objects had gotten the value of 0 for duplicate_id.
>>> Foo.objects.filter(duplicate_id=0).count()
2078
This didn't occur for any of my other ForeignKey fields, only the self-referential one. So I set the values of that field back to None, and this fixed the error.
>>> Foo.objects.filter(duplicate_id=0).update(duplicate=None)
2078L
Because this particular error doesn't point you to a specific field that's causing problems, in general you can check if a ForeignKey field fieldname has any 0 values:
>>> Foo.objects.filter(fieldname_id=0).count()
If this gives a non-zero result, that field probably needs to be fixed.
A long-long time ago there was a problem with Autofield.
https://code.djangoproject.com/ticket/17653
an interesting quotes:
A:
It seems you are trying to save 0 to a ForeignKey which points to an
AutoField. But, this is illegal, as the AutoField will not accept that
value and so the ForeignKey can not hold that value either.
B:
So this fix creates another problem when you need to be able to accept
a value of 0 (or if you are working on a DB that already has a value
of 0!) in an autofield. In my case, I need to accept an ID of zero so
that my foreign key can point to zero so that a unique constraint can
work properly.
It looks like you have 0 in "user"."user_id".
But again... Full StackTrace, please...
I got the same error after upgrading to django 1.7.1
it was caused when saving a model that had a foreign key to another model that for some reason had an id starting auto increment with 0, i guess this was allowed in previous django versions, but not now.

Categories

Resources