diff --git a/dictionary/management/commands/cache_form_qualifiers.py b/dictionary/management/commands/cache_form_qualifiers.py
index c619a0b..d034aae 100644
--- a/dictionary/management/commands/cache_form_qualifiers.py
+++ b/dictionary/management/commands/cache_form_qualifiers.py
@@ -7,7 +7,7 @@ from django.core.management.base import BaseCommand
 from common.util import uniprint
 from export.lexeme_form_query import WHERE_CLAUSES, \
     attr_clauses_combinations, TABLE_FROM_CLAUSES
-from dictionary.models import TableTemplate
+from tables.models import TableTemplate
 
 
 class Command(BaseCommand):
diff --git a/dictionary/management/commands/create_forms.py b/dictionary/management/commands/create_forms.py
index 200f082..6f7e9a8 100644
--- a/dictionary/management/commands/create_forms.py
+++ b/dictionary/management/commands/create_forms.py
@@ -7,7 +7,8 @@ from django.db.transaction import atomic
 from common.util import uniprint
 from export.lexeme_form_query import WHERE_CLAUSES, \
     attr_clauses_combinations, TABLE_FROM_CLAUSES
-from dictionary.models import TableTemplate, Lexeme, LexemeForm
+from dictionary.models import Lexeme, LexemeForm
+from tables.models import TableTemplate
 
 
 class Command(BaseCommand):
diff --git a/dictionary/management/commands/stale/convert_tables.py b/dictionary/management/commands/stale/convert_tables.py
index 7b9e943..11fc523 100644
--- a/dictionary/management/commands/stale/convert_tables.py
+++ b/dictionary/management/commands/stale/convert_tables.py
@@ -3,7 +3,7 @@ from django.core.management import BaseCommand
 from common.util import GroupDict
 from dictionary.models import Cell, TableTemplate, PatternType, TableTemplate, TableCell, TableHeader, \
     TableHeader, LexemeAttribute, ExportCell, InflectionCharacteristic, LexemeAttributeValue
-from tables.models import Variant
+from tables.models import Variant, TableTemplate
 from patterns.models import InflectionType, PatternType
 
 
diff --git a/dictionary/management/commands/stale/import_variant.py b/dictionary/management/commands/stale/import_variant.py
index d918003..2d7e7c4 100644
--- a/dictionary/management/commands/stale/import_variant.py
+++ b/dictionary/management/commands/stale/import_variant.py
@@ -5,7 +5,7 @@ from django.core.management.base import BaseCommand
 from common.util import uniopen
 from dictionary.models import TableTemplate, Cell, TableCell, PartOfSpeech, \
     PatternType, InflectionCharacteristic
-from tables.models import Variant
+from tables.models import Variant, TableTemplate
 from patterns.models import BaseFormLabel, PatternType
 
 
diff --git a/dictionary/migrations/0014_auto_20151213_1328.py b/dictionary/migrations/0014_auto_20151213_1328.py
new file mode 100644
index 0000000..6ddfd4a
--- /dev/null
+++ b/dictionary/migrations/0014_auto_20151213_1328.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dictionary', '0013_auto_20151213_1303'),
+    ]
+
+    database_operations = [
+        migrations.AlterModelTable('tabletemplate', 'tables_tabletemplate'),
+    ]
+
+    operations = [
+        migrations.SeparateDatabaseAndState(
+            database_operations=database_operations),
+    ]
diff --git a/dictionary/migrations/0015_auto_20151213_1328.py b/dictionary/migrations/0015_auto_20151213_1328.py
new file mode 100644
index 0000000..1461a8e
--- /dev/null
+++ b/dictionary/migrations/0015_auto_20151213_1328.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dictionary', '0014_auto_20151213_1328'),
+        ('tables', '0002_tabletemplate'),
+    ]
+
+    state_operations = [
+        migrations.RemoveField(
+            model_name='tabletemplate',
+            name='attribute_values',
+        ),
+        migrations.RemoveField(
+            model_name='tabletemplate',
+            name='attributes',
+        ),
+        migrations.RemoveField(
+            model_name='tabletemplate',
+            name='cell_attributes',
+        ),
+        migrations.RemoveField(
+            model_name='tabletemplate',
+            name='parts_of_speech',
+        ),
+        migrations.RemoveField(
+            model_name='tabletemplate',
+            name='pattern_types',
+        ),
+        migrations.RemoveField(
+            model_name='tabletemplate',
+            name='variant',
+        ),
+        migrations.DeleteModel(
+            name='TableTemplate',
+        ),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='exportcell',
+            name='table_template',
+            field=models.ForeignKey(related_name='export_cells', to='tables.TableTemplate'),
+        ),
+        migrations.AlterField(
+            model_name='tablecell',
+            name='table_template',
+            field=models.ForeignKey(related_name='table_cells', to='tables.TableTemplate'),
+        ),
+        migrations.AlterField(
+            model_name='tableheader',
+            name='table_template',
+            field=models.ForeignKey(related_name='headers', to='tables.TableTemplate'),
+        ),
+        migrations.SeparateDatabaseAndState(state_operations=state_operations),
+    ]
diff --git a/dictionary/models.py b/dictionary/models.py
index 9b878c9..c16921f 100644
--- a/dictionary/models.py
+++ b/dictionary/models.py
@@ -1,7 +1,6 @@
 # -*- coding: utf-8 -*-
 import json
 from collections import OrderedDict
-from itertools import izip
 
 from django.conf import settings
 from django.contrib.auth.models import User, Permission, AnonymousUser
@@ -13,7 +12,6 @@ from accounts.util import users_with_perm
 from common.models import NotDeletedManager
 from common.util import no_history
 from patterns.models import InflectionType, BaseFormLabel, PatternType, Pattern
-from tables.models import Variant
 from tables.util import prepare_table
 
 
@@ -709,6 +707,7 @@ class LexemeInflectionPattern(Model):
 
     def table_template(self, variant, attr_vals=None, pos=None):
         part_of_speech = pos or self.lexeme.part_of_speech
+        from tables.models import TableTemplate
         tts = TableTemplate.objects.filter(
             parts_of_speech=part_of_speech, variant=variant,
             pattern_types=self.pattern.type)
@@ -1010,152 +1009,6 @@ class CrossReference(Model):
         db_table = 'odsylacze'
 
 
-class TableTemplate(Model):
-    name = TextField()
-    variant = ForeignKey(Variant)
-    parts_of_speech = ManyToManyField(PartOfSpeech)
-    pattern_types = ManyToManyField(PatternType)
-    attributes = ManyToManyField(LexemeAttribute)
-    attribute_values = ManyToManyField(LexemeAttributeValue)
-    cell_attributes = ManyToManyField(LexemeAttribute, related_name='templates')
-    takes_gender = BooleanField(default=False)
-
-    def filter_cells_attr(self, cells, attr_vals):
-        for attr in self.cell_attributes.all():
-            attr_val = [a for a in attr_vals if a.attribute == attr]
-            if len(attr_val) != 1:
-                return []
-            cells = cells.filter(attribute_values=attr_val[0])
-        return cells
-
-    def filter_cells(self, pattern_type, gender, attr_vals):
-        if self.variant.type == Variant.TYPE_TABLE:
-            cells = self.table_cells.filter(
-                pattern_types=pattern_type).select_related('base_form_label')
-        else:
-            cells = self.export_cells.filter(
-                pattern_types=pattern_type).select_related('base_form_label')
-        if self.takes_gender and gender:
-            cells = cells.filter(genders=gender)
-        if attr_vals:
-            cells = self.filter_cells_attr(cells, attr_vals)
-        return cells
-
-    def filter_table_headers(self, pattern_type, gender, attr_vals):
-        headers = self.headers.filter(pattern_types=pattern_type)
-        if self.takes_gender and gender:
-            headers = headers.filter(genders=gender)
-        if attr_vals:
-            headers = self.filter_cells_attr(headers, attr_vals)
-        return headers
-
-    def render_with_pattern(self, pattern, *args, **kwargs):
-        base_endings = pattern.base_endings()
-        return self.render(
-            pattern.type, *args, pattern=pattern, base_endings=base_endings,
-            **kwargs)
-
-    def render_with_pattern_type(self, pattern_type, *args, **kwargs):
-        base_endings = pattern_type.dummy_base_endings()
-        return prepare_table(self.render(
-            pattern_type, *args, base_endings=base_endings, numbers=True,
-            **kwargs))
-
-    def render(self, pattern_type, gender, attr_vals, separated=False,
-               numbers=False, pattern=None, **forms_kwargs):
-        table_cells = self.filter_cells(pattern_type, gender, attr_vals)
-        headers = self.filter_table_headers(pattern_type, gender, attr_vals)
-        if table_cells is None or headers is None:
-            return []
-        rows = set()
-        last_col = 0
-        for table_cell in table_cells:
-            rows.add(table_cell.row)
-            col = table_cell.col + table_cell.colspan - 1
-            if col > last_col:
-                last_col = col
-        for header in headers:
-            rows.add(header.row)
-            col = header.col + header.colspan - 1
-            if col > last_col:
-                last_col = col
-        if numbers:
-            last_col += 1
-        table = [[{'type': 'empty'} for i in xrange(last_col)] for row in rows]
-        rows = sorted(rows)
-        if numbers:
-            for row, table_row in izip(rows, table):
-                table_row[0] = {
-                    'type': 'header',
-                    'label': [row],
-                    'css_class': 'blank',
-                    'rowspan': 1,
-                    'colspan': 1}
-        # słownik: nr rzędu w bazie -> rzeczywisty numer rzędu
-        row_translate = dict((r, i) for i, r in enumerate(rows))
-        for tc in table_cells:
-            if numbers:
-                x = tc.col
-            else:
-                x = tc.col - 1
-            y = row_translate[tc.row]
-            table_cell = table[y][x]
-            assert table_cell['type'] != 'span'
-            separator = u'·' if separated else u''
-            forms = [f + (pattern,)
-                     for f in tc.forms(separator=separator, **forms_kwargs)]
-            if not forms:
-                continue
-            if table_cell['type'] == 'empty':
-                table[y][x] = {
-                    'type': 'forms',
-                    'forms': forms,
-                    'rowspan': tc.rowspan,
-                    'colspan': tc.colspan,
-                }
-                for i in xrange(tc.colspan):
-                    for j in xrange(tc.rowspan):
-                        if (i, j) != (0, 0):
-                            assert table[y + j][x + i]['type'] == 'empty'
-                            table[y + j][x + i]['type'] = 'span'
-            else:
-                assert tc.rowspan == table_cell['rowspan']
-                assert tc.colspan == table_cell['colspan']
-                table_cell['forms'] += forms
-        for header in headers:
-            if numbers:
-                x = header.col
-            else:
-                x = header.col - 1
-            y = row_translate[header.row]
-            assert table[y][x]['type'] == 'empty'
-            table[y][x] = {
-                'type': 'label',
-                'label': [header.label],
-                'css_class': header.css_class,
-                'rowspan': header.rowspan,
-                'colspan': header.colspan,
-            }
-            for i in xrange(header.colspan):
-                for j in xrange(header.rowspan):
-                    if (i, j) != (0, 0):
-                        assert table[y + j][x + i]['type'] == 'empty'
-                        table[y + j][x + i]['type'] = 'span'
-        if numbers:
-            first_row = [{
-                'type': 'header',
-                'label': [col if col != 0 else ''],
-                'css_class': 'blank',
-                'rowspan': 1,
-                'colspan': 1} for col in xrange(last_col)]
-            table = [first_row] + table
-        return [row for row in table
-                if not all(cell['type'] == 'empty' for cell in row)]
-
-    def __unicode__(self):
-        return self.name
-
-
 class Cell(Model):
     base_form_label = ForeignKey(BaseFormLabel)
     prefix = CharField(max_length=20, blank=True)
@@ -1227,7 +1080,7 @@ class Cell(Model):
 
 
 class TableCell(Cell):
-    table_template = ForeignKey(TableTemplate, related_name='table_cells')
+    table_template = ForeignKey('tables.TableTemplate', related_name='table_cells')
     pattern_types = ManyToManyField(PatternType)
     genders = ManyToManyField(Gender)
     attribute_values = ManyToManyField(
@@ -1258,7 +1111,7 @@ class TableCell(Cell):
 
 
 class ExportCell(Cell):
-    table_template = ForeignKey(TableTemplate, related_name='export_cells')
+    table_template = ForeignKey('tables.TableTemplate', related_name='export_cells')
     pattern_types = ManyToManyField(PatternType)
     genders = ManyToManyField(Gender)
     attribute_values = ManyToManyField(LexemeAttributeValue)
@@ -1272,7 +1125,7 @@ class ExportCell(Cell):
 
 
 class TableHeader(Model):
-    table_template = ForeignKey(TableTemplate, related_name='headers')
+    table_template = ForeignKey('tables.TableTemplate', related_name='headers')
     pattern_types = ManyToManyField(PatternType)
     genders = ManyToManyField(Gender)
     attribute_values = ManyToManyField(LexemeAttributeValue)
@@ -1332,7 +1185,7 @@ class HomonymNumber(Model):
         for pos in poses)
 
     lexeme = ForeignKey(Lexeme)
-    variant = ForeignKey(Variant)
+    variant = ForeignKey('tables.Variant')
     number = IntegerField()
 
     objects = LexemeNotDeletedManager()
diff --git a/export/lexeme_export.py b/export/lexeme_export.py
index e266a39..f6bfd5c 100644
--- a/export/lexeme_export.py
+++ b/export/lexeme_export.py
@@ -11,9 +11,9 @@ from common.util import debug, flatten, uniprint
 from export.lexeme_form_query import attr_clauses_combinations, \
     EXPORT_FROM_CLAUSES, WHERE_CLAUSES
 from dictionary.models import CrossReferenceType, ClassificationValue, \
-    LexemeAttributeValue, Gender, TableTemplate, HomonymNumber, Lexeme, \
+    LexemeAttributeValue, Gender, HomonymNumber, Lexeme, \
     LexemeAttribute, SavedExportData
-
+from tables.models import TableTemplate
 
 locale.setlocale(locale.LC_ALL, 'pl_PL.utf8')
 
diff --git a/management/ajax_table_view.py b/management/ajax_table_view.py
index a370f61..e7c94b0 100644
--- a/management/ajax_table_view.py
+++ b/management/ajax_table_view.py
@@ -5,9 +5,9 @@ from dictionary.forms import LexemeClosedAttributeForm
 from management.forms import CellRestrictionsForm, GenderForm, \
     AttributeValuesForm, BaseFormLabelForm, CSSClassForm, TemplatePreviewForm, \
     TemplatePreviewGenderForm
-from dictionary.models import TableTemplate, \
-    TableCell, TableHeader, ExportCell, Gender, LexemeAttributeValue
-from tables.models import Variant
+from dictionary.models import TableCell, TableHeader, ExportCell, Gender, \
+    LexemeAttributeValue
+from tables.models import Variant, TableTemplate
 from patterns.models import BaseFormLabel, PatternType
 
 
diff --git a/management/forms.py b/management/forms.py
index 07e6c58..8660d6b 100644
--- a/management/forms.py
+++ b/management/forms.py
@@ -10,7 +10,8 @@ from common.models import FlatPage
 from common.util import GroupDict
 from dictionary.models import Classification, ClassificationValue, Qualifier, \
     QualifierExclusionClass, Lexeme, LexemeInflectionPattern, Vocabulary, \
-    TableTemplate, Gender, LexemeAttributeValue, MultilingualText
+    Gender, LexemeAttributeValue, MultilingualText
+from tables.models import TableTemplate
 from patterns.models import BaseFormLabel, PatternType, Ending
 
 CSS_CLASS_CHOICES = (
diff --git a/tables/management/commands/export_template.py b/tables/management/commands/export_template.py
index 1c35f35..4e527b5 100644
--- a/tables/management/commands/export_template.py
+++ b/tables/management/commands/export_template.py
@@ -1,8 +1,7 @@
 # -*- coding: utf-8 -*-
 from django.core.management.base import BaseCommand
 from common.util import json_encode, uniprint
-from dictionary.models import TableTemplate
-from tables.models import Variant
+from tables.models import Variant, TableTemplate
 
 
 class Command(BaseCommand):
diff --git a/tables/management/commands/export_templates.py b/tables/management/commands/export_templates.py
index cf82ac4..e9115eb 100644
--- a/tables/management/commands/export_templates.py
+++ b/tables/management/commands/export_templates.py
@@ -2,7 +2,7 @@
 from django.core.management.base import BaseCommand
 
 from common.util import uniprint, json_encode
-from dictionary.models import TableTemplate
+from tables.models import TableTemplate
 from tables.management.commands.export_template import export_template
 
 
diff --git a/tables/management/commands/import_template.py b/tables/management/commands/import_template.py
index b6cf9a9..1bb4ad4 100644
--- a/tables/management/commands/import_template.py
+++ b/tables/management/commands/import_template.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 import json
 from django.core.management.base import BaseCommand
-from dictionary.models import TableTemplate, TableCell, \
-    PatternType, LexemeAttributeValue, TableHeader, ExportCell, Gender
-from tables.models import Variant
+from dictionary.models import TableCell, \
+    LexemeAttributeValue, TableHeader, ExportCell, Gender
+from tables.models import Variant, TableTemplate
 from patterns.models import BaseFormLabel, PatternType
 
 
diff --git a/tables/management/commands/import_templates.py b/tables/management/commands/import_templates.py
index 6be9c5c..f4b1b4a 100644
--- a/tables/management/commands/import_templates.py
+++ b/tables/management/commands/import_templates.py
@@ -3,8 +3,8 @@ import json
 
 from django.core.management.base import BaseCommand
 
-from dictionary.models import TableTemplate, LexemeAttribute, \
-    LexemeAttributeValue
+from dictionary.models import LexemeAttribute, LexemeAttributeValue
+from tables.models import TableTemplate
 from patterns.models import PatternType
 from tables.management.commands.import_template import import_template
 
diff --git a/tables/migrations/0002_tabletemplate.py b/tables/migrations/0002_tabletemplate.py
new file mode 100644
index 0000000..92988ae
--- /dev/null
+++ b/tables/migrations/0002_tabletemplate.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('patterns', '0006_auto_20151213_1153'),
+        ('dictionary', '0014_auto_20151213_1328'),
+        ('tables', '0001_initial'),
+    ]
+
+    state_operations = [
+        migrations.CreateModel(
+            name='TableTemplate',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+                ('name', models.TextField()),
+                ('takes_gender', models.BooleanField(default=False)),
+                ('attribute_values', models.ManyToManyField(to='dictionary.LexemeAttributeValue')),
+                ('attributes', models.ManyToManyField(to='dictionary.LexemeAttribute')),
+                ('cell_attributes', models.ManyToManyField(related_name='templates', to='dictionary.LexemeAttribute')),
+                ('parts_of_speech', models.ManyToManyField(to='dictionary.PartOfSpeech')),
+                ('pattern_types', models.ManyToManyField(to='patterns.PatternType')),
+                ('variant', models.ForeignKey(to='tables.Variant')),
+            ],
+        ),
+    ]
+
+    operations = [
+        migrations.SeparateDatabaseAndState(state_operations=state_operations)
+    ]
diff --git a/tables/models.py b/tables/models.py
index 5b621e4..f1f79da 100644
--- a/tables/models.py
+++ b/tables/models.py
@@ -1,5 +1,13 @@
 # -*- coding: utf-8 -*-
-from django.db.models import Model, CharField
+from itertools import izip
+
+from django.db.models import Model, CharField, TextField, ForeignKey, \
+    ManyToManyField, BooleanField
+
+from dictionary.models import PartOfSpeech, LexemeAttribute, \
+    LexemeAttributeValue
+from patterns.models import PatternType
+from tables.util import prepare_table
 
 
 class Variant(Model):
@@ -18,3 +26,149 @@ class Variant(Model):
 
     class Meta:
         db_table = 'warianty'
+
+
+class TableTemplate(Model):
+    name = TextField()
+    variant = ForeignKey(Variant)
+    parts_of_speech = ManyToManyField(PartOfSpeech)
+    pattern_types = ManyToManyField(PatternType)
+    attributes = ManyToManyField(LexemeAttribute)
+    attribute_values = ManyToManyField(LexemeAttributeValue)
+    cell_attributes = ManyToManyField(LexemeAttribute, related_name='templates')
+    takes_gender = BooleanField(default=False)
+
+    def filter_cells_attr(self, cells, attr_vals):
+        for attr in self.cell_attributes.all():
+            attr_val = [a for a in attr_vals if a.attribute == attr]
+            if len(attr_val) != 1:
+                return []
+            cells = cells.filter(attribute_values=attr_val[0])
+        return cells
+
+    def filter_cells(self, pattern_type, gender, attr_vals):
+        if self.variant.type == Variant.TYPE_TABLE:
+            cells = self.table_cells.filter(
+                pattern_types=pattern_type).select_related('base_form_label')
+        else:
+            cells = self.export_cells.filter(
+                pattern_types=pattern_type).select_related('base_form_label')
+        if self.takes_gender and gender:
+            cells = cells.filter(genders=gender)
+        if attr_vals:
+            cells = self.filter_cells_attr(cells, attr_vals)
+        return cells
+
+    def filter_table_headers(self, pattern_type, gender, attr_vals):
+        headers = self.headers.filter(pattern_types=pattern_type)
+        if self.takes_gender and gender:
+            headers = headers.filter(genders=gender)
+        if attr_vals:
+            headers = self.filter_cells_attr(headers, attr_vals)
+        return headers
+
+    def render_with_pattern(self, pattern, *args, **kwargs):
+        base_endings = pattern.base_endings()
+        return self.render(
+            pattern.type, *args, pattern=pattern, base_endings=base_endings,
+            **kwargs)
+
+    def render_with_pattern_type(self, pattern_type, *args, **kwargs):
+        base_endings = pattern_type.dummy_base_endings()
+        return prepare_table(self.render(
+            pattern_type, *args, base_endings=base_endings, numbers=True,
+            **kwargs))
+
+    def render(self, pattern_type, gender, attr_vals, separated=False,
+               numbers=False, pattern=None, **forms_kwargs):
+        table_cells = self.filter_cells(pattern_type, gender, attr_vals)
+        headers = self.filter_table_headers(pattern_type, gender, attr_vals)
+        if table_cells is None or headers is None:
+            return []
+        rows = set()
+        last_col = 0
+        for table_cell in table_cells:
+            rows.add(table_cell.row)
+            col = table_cell.col + table_cell.colspan - 1
+            if col > last_col:
+                last_col = col
+        for header in headers:
+            rows.add(header.row)
+            col = header.col + header.colspan - 1
+            if col > last_col:
+                last_col = col
+        if numbers:
+            last_col += 1
+        table = [[{'type': 'empty'} for i in xrange(last_col)] for row in rows]
+        rows = sorted(rows)
+        if numbers:
+            for row, table_row in izip(rows, table):
+                table_row[0] = {
+                    'type': 'header',
+                    'label': [row],
+                    'css_class': 'blank',
+                    'rowspan': 1,
+                    'colspan': 1}
+        # słownik: nr rzędu w bazie -> rzeczywisty numer rzędu
+        row_translate = dict((r, i) for i, r in enumerate(rows))
+        for tc in table_cells:
+            if numbers:
+                x = tc.col
+            else:
+                x = tc.col - 1
+            y = row_translate[tc.row]
+            table_cell = table[y][x]
+            assert table_cell['type'] != 'span'
+            separator = u'·' if separated else u''
+            forms = [f + (pattern,)
+                     for f in tc.forms(separator=separator, **forms_kwargs)]
+            if not forms:
+                continue
+            if table_cell['type'] == 'empty':
+                table[y][x] = {
+                    'type': 'forms',
+                    'forms': forms,
+                    'rowspan': tc.rowspan,
+                    'colspan': tc.colspan,
+                }
+                for i in xrange(tc.colspan):
+                    for j in xrange(tc.rowspan):
+                        if (i, j) != (0, 0):
+                            assert table[y + j][x + i]['type'] == 'empty'
+                            table[y + j][x + i]['type'] = 'span'
+            else:
+                assert tc.rowspan == table_cell['rowspan']
+                assert tc.colspan == table_cell['colspan']
+                table_cell['forms'] += forms
+        for header in headers:
+            if numbers:
+                x = header.col
+            else:
+                x = header.col - 1
+            y = row_translate[header.row]
+            assert table[y][x]['type'] == 'empty'
+            table[y][x] = {
+                'type': 'label',
+                'label': [header.label],
+                'css_class': header.css_class,
+                'rowspan': header.rowspan,
+                'colspan': header.colspan,
+            }
+            for i in xrange(header.colspan):
+                for j in xrange(header.rowspan):
+                    if (i, j) != (0, 0):
+                        assert table[y + j][x + i]['type'] == 'empty'
+                        table[y + j][x + i]['type'] = 'span'
+        if numbers:
+            first_row = [{
+                'type': 'header',
+                'label': [col if col != 0 else ''],
+                'css_class': 'blank',
+                'rowspan': 1,
+                'colspan': 1} for col in xrange(last_col)]
+            table = [first_row] + table
+        return [row for row in table
+                if not all(cell['type'] == 'empty' for cell in row)]
+
+    def __unicode__(self):
+        return self.name
\ No newline at end of file