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:

  1. the migration directory of the blog app shouldn’t be deleted.
  2. 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.

Asked By: Shahriar.M

||

Answers:

I think setting the managed option to False in the metadata of the two models can help you, according to the Django document.

Answered By: Mohammad Abbasi

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’.

Answered By: abhi54

** 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 **

  1. Comment the field you want to alter.
  2. If you have created form for that model, please comment out your target field name in the form.
  3. Do make migrations. This will delete your target field.
  4. 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.
  5. Add your required foreign key field in your model.
  6. 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.)
  7. Do migrate.
Answered By: Akash Bhandari