4

I have two models which I want to relate: User and Group. Each user belongs to a group. I've tried to create a default user by using in get_or_create():

group = models.ForeignKey(Group.objects.get_or_create(name="Free")[0])

But it raises the following error:

(fields.E300) Field defines a relation with model 'Group', which is either not installed, or is abstract.

What can I do to fix this issue?

Each user must have a non-null group value. So I've read about this get_or_create() method. But I've also seen that it can return more than one object... and I don't want it to happen. I thought about creating a unique name parameter but is there a better solution for it?

Can you help me, please? I appreciate your help.

Jaqueline Passos
  • 1,301
  • 2
  • 24
  • 37
  • 1
    To explain the error - code that is not inside a function, such as the line in your question, is executed as soon as your `models.py` file is loaded by Python. This happens early in the start-up of your Django process, when Django looks for a models.py file in each of the `INSTALLED_APPS` and imports it. The problem is that you don't know which other models have been imported yet. The error here is because the `Group` model (from `django.auth.models`) has not been imported yet, so it is as if it doesn't exist (yet). – Anentropic Dec 26 '15 at 02:36
  • 1
    as others have shown in answers, you can put the `Group.objects.get_or_create(name="Free")[0]` in a function so that it is not executed immediately, Django will instead call the function only when it needs to know the value. At this point all the models in your project, and Django's own models, will have been imported and it will work – Anentropic Dec 26 '15 at 02:37

2 Answers2

4

A more comprehensive answer can be found here: How to set a Django model field's default value to a function call / callable (e.g., a date relative to the time of model object creation)

You need to specifify the related Model and set the default.

class User(models.Model):
    def default_group(self):
        return Group.objects.get_or_create(name="Free")[0]

    group = models.ForeignKey('app_name.Group', default=default_group)

Your default value would be evaluated at model definition time, but Django allows you to provide a callable as default, which is called for each instance creation.

Community
  • 1
  • 1
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • 2
    This seems to fail for me while running migrate: `TypeError: default_obj() missing 1 required positional argument: 'self'` – Jacek Jul 05 '21 at 09:16
1

To explain the error - code that is not inside a function, such as the line in your question, is executed as soon as your models.py file is loaded by Python. This happens early in the start-up of your Django process, when Django looks for a models.py file in each of the INSTALLED_APPS and imports it. The problem is that you don't know which other models have been imported yet. The error here is because the Group model (from django.auth.models) has not been imported yet, so it is as if it doesn't exist (yet).

Others have suggested you could put the Group.objects.get_or_create(name="Free")[0] in a function so that it is not executed immediately, Django will instead call the function only when it needs to know the value. At this point all the models in your project, and Django's own models, will have been imported and it will work.

Regarding the second part of your question... yes, any time you use get or get_or_create methods you need to query on a unique field otherwise you may get MultipleObjectsReturned exception.

In fact I think you should not use get_or_create for what you are trying to do here. Instead you should use an initial data fixture:
https://docs.djangoproject.com/en/1.9/howto/initial-data/
...to ensure that the default group already exists (and with a known primary key value) before you run your site.

That way you will know the unique pk of the default Group and you can do a get query:

def default_group():
    return Group.objects.get(pk=1)

class YourModel(models.model):
    group = models.ForeignKey(Group, default=default_group)
Anentropic
  • 32,188
  • 12
  • 99
  • 147
  • I've created it and it worked when I had the Group created via the admin screen. However, when I deleted the database and tested it again, it didn't worked. It seems like the Group is not being created by the fixture. When I create it, it says `Installed 1 object(s) from 1 fixture(s)` but when I run the command on the shell, it returns an empty array. `Group.objects.all() []` .I don't know why. Do you have any clue? – Jaqueline Passos Jan 10 '16 at 23:21
  • have a look in the database to see what's been created by the fixture – Anentropic Jan 12 '16 at 09:38