How to insert data in specific category if it is not defined in Django model's field?

I have a Django project where I created two models: Category and Shop. Each shop might have only one category. If I didn't define a shop's category I want it to be in Without category section at template. How do I set a default value?

My models:

class Category(models.Model):
    name = models.CharField(max_length=100)
    position = models.IntegerField(unique=True)

    def __str__(self):
        return f'{self.name}'


class DemoShop(models.Model):
    title = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE,
                             related_name='Cat')

    def __str__(self):
        return f"{self.title}"

When I write:

category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='Cat', default='Without category')

It has no effect in my database and It doesn't show in Without category section at my template. If I haven't put a shop in a certain category I want it to be shown in Without category at the page, like:

Products:
    -lorem;
    -testshop;
Watch:
    -keram;
    -pollop;
Without category:
    (All shop what I haven't define a category in DB)

The ForeignKey model field default value is the primary key of the model instance it references (unless you set to_field on your ForeignKey to point to some other field of the referenced model). Please refer to https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.Field.default

If you want to set the default category for the DemoShop to be "Without value" you can create a classmethod that creates/returns if exists the Category of the name "Without category" (I arbitrarily chose the position=5 argument value for the get_or_create method):

class Category(models.Model):
   name = models.CharField(max_length=100)
   position = models.IntegerField(unique=True)

   def __str__(self):
       return f'{self.name}'

   @classmethod
   def get_default_pk(cls):
       obj, created = cls.objects.get_or_create(
           name="Without category",
           position=5
       )
       return obj.pk

Then you can use the defined classmethod to get your dummy category of the name "Without category" (assuming that Category and DemoShop models are defined in the same models.py file:

class DemoShop(models.Model):
    title = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE,
                             related_name='Cat', default=Category.get_default_pk())

If for some reason you really cannot/don't want to insert the dummy category of the name "Without category" into your database, you can set the category field on your DemoShop model to allow for blank input and to be nullable and then define a custom method as a getter for the related category name:

class DemoShop(models.Model):
    title = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE,
                             related_name='Cat', blank=True, null=True)

    def __str__(self):
        return f"{self.title}"

    def get_category_name(self):
        if self.category is None:
            return "Without category"
        return self.category.name
        

And then use this method in your template to get the category name for your DemoShop instances.

Back to Top