﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
24853	FK value not inserted in database in data migration	Rakan Alhneiti	nobody	"Hello,

I am using ""django_dynamic_scraper"" to scrape data off the internet. I started my project by creating an empty migration that basically adds a default scraper.


Models as defined in dynamic_scraper app:
{{{
class ScrapedObjClass(models.Model):
    name = models.CharField(max_length=200)
    scraper_scheduler_conf = models.TextField(default='\
""MIN_TIME"": 15,\n\
""MAX_TIME"": 10080,\n\
""INITIAL_NEXT_ACTION_FACTOR"": 10,\n\
""ZERO_ACTIONS_FACTOR_CHANGE"": 20,\n\
""FACTOR_CHANGE_FACTOR"": 1.3,\n')
    checker_scheduler_conf = models.TextField(default='\
""MIN_TIME"": 1440,\n\
""MAX_TIME"": 10080,\n\
""INITIAL_NEXT_ACTION_FACTOR"": 1,\n\
""ZERO_ACTIONS_FACTOR_CHANGE"": 5,\n\
""FACTOR_CHANGE_FACTOR"": 1.3,\n')
    comments = models.TextField(blank=True)
    
    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name',]


class ScrapedObjAttr(models.Model):
    ATTR_TYPE_CHOICES = (
        ('S', 'STANDARD'),
        ('T', 'STANDARD (UPDATE)'),
        ('B', 'BASE'),
        ('U', 'DETAIL_PAGE_URL'),
        ('I', 'IMAGE'),
    )
    name = models.CharField(max_length=200)
    obj_class = models.ForeignKey(ScrapedObjClass)
    attr_type = models.CharField(max_length=1, choices=ATTR_TYPE_CHOICES)
    
    def __unicode__(self):
        return self.name + "" ("" + self.obj_class.__unicode__() + "")""
}}}

Here's my migration:

{{{
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


def add_youtube_scraper(apps, schema_editor):
    Scraper = apps.get_model('dynamic_scraper', 'Scraper')
    ScrapedObjClass = apps.get_model('dynamic_scraper', 'ScrapedObjClass')
    ScrapedObjAttr = apps.get_model('dynamic_scraper', 'ScrapedObjAttr')
    ScraperElem = apps.get_model('dynamic_scraper', 'ScraperElem')

    scraped_obj_class = ScrapedObjClass()
    scraped_obj_class.name = 'Youtube Video'
    scraped_obj_class.save()

    scraped_attrs_map = {}
    scraped_attrs_list = [
        {'name': 'base', 'type': 'B'},
        {'name': 'url', 'type': 'U'},
        {'name': 'title', 'type': 'S'},
        {'name': 'body', 'type': 'S'},
        {'name': 'images', 'type': 'I'},
        {'name': 'videos', 'type': 'S'},
    ]

    for scraped_attr in scraped_attrs_list:
        scraped_obj_attr = ScrapedObjAttr()
        scraped_obj_attr.name = scraped_attr['name']
        scraped_obj_attr.attr_type = scraped_attr['type']
        scraped_obj_attr.obj_class_id = scraped_obj_class.id
        scraped_obj_attr.save()
        scraped_attrs_map[scraped_attr['name']] = scraped_obj_attr


class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.RunPython(add_youtube_scraper)
    ]

}}}


When i run python manage.py migrate i get the following error:

{{{
Running migrations:
  Applying content_scraper.0001_initial...
Traceback (most recent call last):
  File ""./manage.py"", line 11, in <module>
    execute_from_command_line(sys.argv)
  File ""/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py"", line 385, in execute_from_command_line
    utility.execute()
  File ""/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py"", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File ""/usr/local/lib/python2.7/site-packages/django/core/management/base.py"", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File ""/usr/local/lib/python2.7/site-packages/django/core/management/base.py"", line 338, in execute
    output = self.handle(*args, **options)
  File ""/usr/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py"", line 161, in handle
    executor.migrate(targets, plan, fake=options.get(""fake"", False))
  File ""/usr/local/lib/python2.7/site-packages/django/db/migrations/executor.py"", line 68, in migrate
    self.apply_migration(migration, fake=fake)
  File ""/usr/local/lib/python2.7/site-packages/django/db/migrations/executor.py"", line 102, in apply_migration
    migration.apply(project_state, schema_editor)
  File ""/usr/local/lib/python2.7/site-packages/django/db/migrations/migration.py"", line 108, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File ""/usr/local/lib/python2.7/site-packages/django/db/migrations/operations/special.py"", line 117, in database_forwards
    self.code(from_state.render(), schema_editor)
  File ""/app/content_scraper/migrations/0001_initial.py"", line 32, in add_youtube_scraper
    scraped_obj_attr.save()
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/base.py"", line 589, in save
    force_update=force_update, update_fields=update_fields)
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/base.py"", line 617, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/base.py"", line 698, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/base.py"", line 731, in _do_insert
    using=using, raw=raw)
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/manager.py"", line 92, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/query.py"", line 921, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File ""/usr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py"", line 921, in execute_sql
    cursor.execute(sql, params)
  File ""/usr/local/lib/python2.7/site-packages/django/db/backends/utils.py"", line 82, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File ""/usr/local/lib/python2.7/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
  File ""/usr/local/lib/python2.7/site-packages/django/db/utils.py"", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File ""/usr/local/lib/python2.7/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: null value in column ""obj_class_id"" violates not-null constraint
DETAIL:  Failing row contains (19, base, null, B).
}}}

Basically what i am trying to do is assign a value to a ForeignKey. I tried printing the value of the created scraper object class and it's 19 as in the last line of the traceback. I also checked the SQL statement generated:

{{{
INSERT INTO ""dynamic_scraper_scrapedobjattr"" (""name"", ""attr_type"") VALUES (%s, %s) RETURNING ""dynamic_scraper_scrapedobjattr"".""id""
}}}

As you can see the obj_class attribute of the ScrapedObjAttr is omitted, which is a weird behaviour."	Uncategorized	closed	Database layer (models, ORM)	1.7	Normal	wontfix	database, migrations		Unreviewed	0	0	0	0	0	0
