7

I want to create data migrations for a model(Comment) which has a GenericForeignKey relation. My model was made according to django documentation for contenttypes.

Models:

...
class NiceMeme(models.Model):
    """
        Example model.
    """

    name = models.CharField(max_length=140)
    image = models.ImageField(upload_to=get_path_to_store_nice_meme_images)


class Comment(models.Model):
    """
        Model to add comments to any other (non abstract) model.
    """
    ...
    user = models.ForeignKey(ExtendedUser)
    content = models.CharField(max_length=140)
    content_type = models.ForeignKey(ContentType)
    object_pk = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_pk')

Data migration:

...
def create_comment(apps, schema_editor):
    ...
    nice_meme = NiceMeme.objects.create(name='Nice nice meme')
    Comment.objects.create(
        user=user,
        content='Gott ist tot',
        poster_username='Friedrich',
        content_object=nice_meme
    )

...
operations = [
    migrations.RunPython(create_comment)
]

When I run ./manage.py migrate I get:

TypeError: 'content_object' is an invalid keyword argument for this function

I have to say that I have used same code as create_comment inside a view and works well.

Im using django 1.7.7. Im not using south.

Edit: I tried Shang Wang's answer.

Comment.objects.create(
    user=user,
    content='Gott ist tot', 
    poster_username='Friedrich',
    content_type=ContentType.objects.get_for_model(nice_meme),
    object_pk=nice_meme.id
) 

Is not working either:

ValueError: Cannot assign "<ContentType: nice meme>": "Comment.content_type"  must be a "ContentType" instance.
Laraconda
  • 667
  • 6
  • 15

3 Answers3

17

As I said, I've been through this same problem and a colleague helped me with this tip:

You really need to set content_type and object_pk as +Shang Wang pointed out, but ContentType must be loaded using apps.get_model instead of directly import it.

So use this:

ContentType = apps.get_model('contenttypes', 'ContentType')

In your migration method and all should work :)

def create_comment(apps, schema_editor):
    ...
    ContentType = apps.get_model('contenttypes', 'ContentType')
    nice_meme = NiceMeme.objects.create(name='Nice nice meme')
    Comment.objects.create(
        user=user,
        content='Gott ist tot',
        poster_username='Friedrich',
        content_type=ContentType.objects.get_for_model(nice_meme),
        object_pk=nice_meme.id
    )
Rafael Verger
  • 1,751
  • 13
  • 18
  • Is not working that way. `ContentType.objects` is actually `django.db.models.manager.Manager` so what I did was: `nice_meme_contenttype = ContentType.objects.get( app_label='comments', model='nicememe' )` model name must be lowercase. And now is working :) – Laraconda Nov 20 '15 at 00:54
  • Weird @LaraChícharo ... did you load ContentType using apps.get_model? I'm glad you've solved your problem BTW :) – Rafael Verger Nov 23 '15 at 17:41
0

Please try this:

from django.contrib.contenttypes.models import ContentType

nice_meme = NiceMeme.objects.create(name='Nice nice meme')
Comment.objects.create(user=user,
                       content='Gott ist tot', 
                       poster_username='Friedrich',
                       content_type=ContentType.objects.get_for_model(nice_meme),
                       object_pk=nice_meme.id)

I think the problem is that your content_object field is just a simple way for your Comment model objects to access the foreignkey quickly, like:

obj = some_comment.content_object

It's not an actual field but a combination of 2 fields, so you cannot directly assign one single NiceMeme object to it.

Edit:

Sounds like you are using South, there's an issue described here. The solution is answered in another SO thread. Sounds like the solution is to freeze any model that your migration is related:

python manage.py schemamigration --auto yourapp --freeze contenttypes

You might need to freeze more apps:

python manage.py schemamigration --auto yourapp --freeze contenttypes --freeze someotherapp ...

I never encountered this problem before, so please read original post for more details, hope this helps.

Community
  • 1
  • 1
Shang Wang
  • 24,909
  • 20
  • 73
  • 94
  • Thank you for your answer. Unfortunately, I got this: `ValueError: Cannot assign "": "Comment.content_type" must be a "ContentType" instance.` – Laraconda Oct 31 '15 at 01:11
  • I updated my answer, I don't have enough knowledge to deal with this, but try the thread I found see if it helps. – Shang Wang Oct 31 '15 at 01:32
  • Im not using south, Im using django 1.7.7. Sorry for telling you until now. Thanks for your help. – Laraconda Oct 31 '15 at 01:42
0

I had the same problem, the solution is to get ContentType object with the model name in lowercase:

content=ContentType.objects.get(app_label='appname', model='modelname')

For this question:

def create_comment(apps, schema_editor):
    ContentType = apps.get_model('contenttypes', 'ContentType')    
    nice_meme = NiceMeme.objects.create(name='Nice nice meme')

    Comment.objects.create(
        user=user,
        content=ContentType.objects.get(app_label='appname', model='nicememe')
        poster_username='Friedrich',
        content_object=nice_meme
    )
okay
  • 190
  • 2
  • 10