django: default for non-nullable field - python

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.

Related

Django asking for default value during migration

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.

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 Two Model Fields, same DB Column

We are trying to work with legacy DB Tables that were generated outside of Django and are not structured in an ideal way. We also can not modify the existing tables.
The DB uses the same user ID (pk) across all the tables, wether or not there is a record for that user ID. It also uses that ID as a PK on the other tables, rather than rely on them to auto increment their own IDs.
So imagine something like this below:
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
class User(models.Model):
user_id = models.IntegerField(primary_key=True)
class UserTypeA(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
class UserTypeB(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
What we thought of creating a relationship between Items and UserTypeA (as well as UserTypeB) is to create another field entry that uses the same column as the user_id.
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
user_type_a = models.ForeignKey('UserTypeA', db_column='UserID')
user_type_b = models.ForeignKey('UserTypeB', db_column='UserID')
This unfortunately returns a "db_column is already used" type error.
Any thoughts on how to better approach the way what we're trying to do?
A detail to note is that we're only ever reading from this databases (no updates to), so a read-only solution is fine.
Thanks,
-RB
I've solved a similar problem with this (this code should be put before the definition of your Model):
from django.db.models.signals import class_prepared
def remove_field(sender, **kwargs):
if sender.__name__ == "MyModel":
sender._meta.local_fields.remove(sender.myFKField.field)
class_prepared.connect(remove_field)
(Tested in Django 1.5.11)
Django uses local_fields to make the CREATE TABLE query.
So, I've just attached the signal class_prepared and check if sender equals the class I was expecting. If so, I've removed the field from that list.
After doing that, the CREATE TABLE query didn't include the field with same db_column and the error did not ocurr.
However the Model still working properly (with manager methods properly populating the removed field from local_fields), I can't tell the real impact of that.

Provide a default for ForeignKey field on existing entries in Django

I have this model:
class Movie(models.Model):
# here are some fields for this model
to which I added the following field (the database was already populated with Movie models):
user = models.ForeignKey(User, default=1)
I ran the commands 'makemigrations' and then 'migrate':
python manage.py makemigrations myapp
python manage.py migrate
but it doesn't work. What I want to do is to add the 'user' field to Movie objects and provide a default for it for all the existing Movie objects in my database (in this case the default is the User object with id=1).
Another thing that I tried is to leave it without the default value and then, when i run the 'makemigrations' command, to give it the default value 1 (by selecting the "provide a one-off default now" option). In both cases, when I run the 'migrate' command I get an IntegrityError:
django.db.utils.IntegrityError: movies_movie__new.user_id may not be NULL
I also checked the ids for the Users that are already in the database to make sure that a User with id=1 exists and it does. So why doesn't it work? Thank you.
If you add "null=True" it works:
user = models.ForeignKey(User, default=1, null=True)
Then
python manage.py makemigrations movies
Migrations for 'movies':
0003_auto_20150316_0959.py:
...
- Add field user to Movie
...
Then
python manage.py migrate movies
The database should look like:
id|user_id|name
1|1|movie_name
2|1|movie_2
3|1|movie_3
...
All the empty user_ids get a value of 1. So you're done.
Now, if you need to make that field required, just change the model back to
user = models.ForeignKey(User, default=1)
make another migration
and migrate again
This time it will work since all fields have user_id.
;-)

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