how to alter model field to foreign key with existing tables
Question:
I have a simple model. This table has a few entries in the db. And, the category
field of them is not empty:
# blog.models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=100)
category = models.CharField(max_length=50)
I want to change the category
field to foreign key.
The category
table is created as follows and those fields are changed to foreign keys:
# blog.models.py
from django.db import models
from account.models import User
class Category(models.Model):
title = models.CharField(max_length=50)
def __str__(self):
return self.title
class Article(models.Model):
title = models.CharField(max_length=100)
# category = models.CharField(max_length=50)
category = models.ForeignKey(Category, on_delete=models.SET_NULL,
null=True, blank=True,
default=Category.objects.get(title=title))
I have these restrictions:
- the
migration
directory of the blog app shouldn’t be deleted.
- the
category
key should point to a category object that has the same title
equal to its own. If a category object gets deleted, the category field of articles pointing to it should become null.
Here is my problem:
When I perform migrate
, django says
raise self.model.DoesNotExist( blog.models.Category.DoesNotExist:
Category matching query does not exist.
This is because I have a few articles. But, the category table is empty. So, Django doesn’t find any category object to point existing articles to.
I tried to deleted category
field’s default value:
category = models.ForeignKey(Category, on_delete=models.SET_NULL,
null=True, blank=True )
But, migrate
gives this error:
raise IntegrityError( django.db.utils.IntegrityError: The row in
table ‘blog_article’ with primary key ‘1’ has an invalid foreign key:
blog_article.category_id contains a value ‘Calculus’ that does not
have a corresponding value in blog_category.id.
What is the proper way to alter a model field into a foreign key that points to an existing table that contains some data.
Answers:
I think setting the managed option to False in the metadata of the two models can help you, according to the Django document.
You can use the to_field
to point to a Category object
class Article(models.Model):
title = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, to_field='title')
Herein to_field='title'
the string ‘title’ is used as ForeignKey field to point to the Category model’s field ‘title’.
** Here is a solution – If you don’t care about your existing data in your target table please follow below steps this will definitely solve your issue **
- Comment the field you want to alter.
- If you have created form for that model, please comment out your target field name in the form.
- Do make migrations. This will delete your target field.
- Do migrate. (If getting an error then delete that field in the DB model, and add a field with the same name. This will solve migrate error).
Now we have deleted the target field from local as well as DB.
- Add your required foreign key field in your model.
- Do make migrations. (In doing this, you have to give a default value, make sure your given id is present in your foreign key table.)
- Do migrate.
I have a simple model. This table has a few entries in the db. And, the category
field of them is not empty:
# blog.models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=100)
category = models.CharField(max_length=50)
I want to change the category
field to foreign key.
The category
table is created as follows and those fields are changed to foreign keys:
# blog.models.py
from django.db import models
from account.models import User
class Category(models.Model):
title = models.CharField(max_length=50)
def __str__(self):
return self.title
class Article(models.Model):
title = models.CharField(max_length=100)
# category = models.CharField(max_length=50)
category = models.ForeignKey(Category, on_delete=models.SET_NULL,
null=True, blank=True,
default=Category.objects.get(title=title))
I have these restrictions:
- the
migration
directory of the blog app shouldn’t be deleted. - the
category
key should point to a category object that has the sametitle
equal to its own. If a category object gets deleted, the category field of articles pointing to it should become null.
Here is my problem:
When I perform migrate
, django says
raise self.model.DoesNotExist( blog.models.Category.DoesNotExist:
Category matching query does not exist.
This is because I have a few articles. But, the category table is empty. So, Django doesn’t find any category object to point existing articles to.
I tried to deleted category
field’s default value:
category = models.ForeignKey(Category, on_delete=models.SET_NULL,
null=True, blank=True )
But, migrate
gives this error:
raise IntegrityError( django.db.utils.IntegrityError: The row in
table ‘blog_article’ with primary key ‘1’ has an invalid foreign key:
blog_article.category_id contains a value ‘Calculus’ that does not
have a corresponding value in blog_category.id.
What is the proper way to alter a model field into a foreign key that points to an existing table that contains some data.
I think setting the managed option to False in the metadata of the two models can help you, according to the Django document.
You can use the to_field
to point to a Category object
class Article(models.Model):
title = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, to_field='title')
Herein to_field='title'
the string ‘title’ is used as ForeignKey field to point to the Category model’s field ‘title’.
** Here is a solution – If you don’t care about your existing data in your target table please follow below steps this will definitely solve your issue **
- Comment the field you want to alter.
- If you have created form for that model, please comment out your target field name in the form.
- Do make migrations. This will delete your target field.
- Do migrate. (If getting an error then delete that field in the DB model, and add a field with the same name. This will solve migrate error).
Now we have deleted the target field from local as well as DB. - Add your required foreign key field in your model.
- Do make migrations. (In doing this, you have to give a default value, make sure your given id is present in your foreign key table.)
- Do migrate.