7

Here is my situation: SubCategory has foreign key to Topic and Topic has foreign key to SubCategory.

class SubCategory(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=110)
    description = models.TextField(default='')
    ordering = models.PositiveIntegerField(default=1)
    category = models.ForeignKey(Category)
    created_on = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User)
    updated_on = models.DateTimeField(blank=True, null=True)
    updated_by = models.ForeignKey(User, related_name='+')
    num_topics = models.IntegerField(default=0)
    num_posts = models.IntegerField(default=0)
    last_topic = models.ForeignKey(Topic, related_name='+')


class Topic(models.Model):
    name = models.CharField(max_length=300)
    slug = models.SlugField(max_length=300)
    description = models.TextField(default='')
    subcategory = models.ForeignKey(SubCategory)
    created_on = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User)
    updated_on = models.DateTimeField(blank=True, null=True)
    updated_by = models.ForeignKey(User, related_name='+')

When I run this code, it gives the following error:

NameError: name 'Topic' is not defined.

Can anybody tell me how to fix it?

asit_dhal
  • 1,239
  • 19
  • 35

4 Answers4

12

Either put Topic in quotes: "Topic"

last_topic = models.ForeignKey("Topic", related_name='+')

or put the Topic class above the SubCategory class

Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
  • 4
    I'd like to point out that the '.' syntax exists as well. Thus, 'auth.User' is an easy way to make a foreign key to django.contrib.auth.models.User – Delyan Sep 28 '13 at 21:07
  • Yea exactly, that's useful when the model you are referencing isn't in the current file. Also when you are trying to avoid circular imports. When the model *is* in the current file you can forgo the app reference – Timmy O'Mahony Sep 28 '13 at 21:37
  • 2
    what does the related_name='+' do? – Rakesh Gopal Aug 16 '18 at 17:49
  • 1
    @RakeshGopal as [docs](https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name) say it tells Django not to create backward relation – devaerial Feb 25 '20 at 13:18
0

Your problem is that Topic is declared after Subcategory and hence it is not available when Subcategory is defined.

Python has no partial class declaration or forward declaration. But you can use the init method to achieve something similar. See here for details.

Community
  • 1
  • 1
papirrin
  • 2,004
  • 22
  • 30
0

Try enclosing the models with quotes:

class SubCategory(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=110)
    description = models.TextField(default='')
    ordering = models.PositiveIntegerField(default=1)
    category = models.ForeignKey('Category')
    created_on = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey('User')
    updated_on = models.DateTimeField(blank=True, null=True)
    updated_by = models.ForeignKey('User', related_name='+')
    num_topics = models.IntegerField(default=0)
    num_posts = models.IntegerField(default=0)
    last_topic = models.ForeignKey('Topic', related_name='+')


class Topic(models.Model):
    name = models.CharField(max_length=300)
    slug = models.SlugField(max_length=300)
    description = models.TextField(default='')
    subcategory = models.ForeignKey("SubCategory")
    created_on = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey('User')
    updated_on = models.DateTimeField(blank=True, null=True)
    updated_by = models.ForeignKey('User', related_name='+')
Rafa He So
  • 473
  • 3
  • 12
-1

There is several solutions to your problem: you could either define a back reference, from SubCategory to Topic through the related_name ForeignKey attribute, or simply pass the name of your ForeignKey model as a string.

Solution 1:

class SubCategory(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=110)
    description = models.TextField(default='')
    ordering = models.PositiveIntegerField(default=1)
    ...
    last_topic = models.ForeignKey(Topic, related_name='subcategory')

Solution 2:

class SubCategory(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=110)
    description = models.TextField(default='')
    ordering = models.PositiveIntegerField(default=1)
    category = models.ForeignKey(Category)
    created_on = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User)
    updated_on = models.DateTimeField(blank=True, null=True)
    updated_by = models.ForeignKey(User, related_name='+')
    num_topics = models.IntegerField(default=0)
    num_posts = models.IntegerField(default=0)
    last_topic = models.ForeignKey("Topic", related_name='+')


class Topic(models.Model):
    name = models.CharField(max_length=300)
    slug = models.SlugField(max_length=300)
    description = models.TextField(default='')
    subcategory = models.ForeignKey(SubCategory)
    created_on = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User)
    updated_on = models.DateTimeField(blank=True, null=True)
    updated_by = models.ForeignKey(User, related_name='+')

    ...
Balthazar Rouberol
  • 6,822
  • 2
  • 35
  • 41