diff --git a/dictionary/ajax_lexeme_view.py b/dictionary/ajax_lexeme_view.py
index d75bb4c..e72d91d 100644
--- a/dictionary/ajax_lexeme_view.py
+++ b/dictionary/ajax_lexeme_view.py
@@ -1,26 +1,24 @@
 # -*- coding: utf-8 -*-
-from django.utils import timezone
-
 from django.core.cache import cache
+from django.db.models import Max
 from django.shortcuts import get_object_or_404
+from django.utils import timezone
 from django.utils.encoding import force_unicode
 from django.utils.translation import ugettext as _
-from django.db.models import Max
 
+from common.decorators import ajax, AjaxError, render_ajax
+from common.util import error_messages, bisect_left, format_date
 from dictionary.ajax_lexeme_slickgrid import LexemeQuery
 from dictionary.auto_derivatives import lexeme_derivatives, create_derivative
-from dictionary.models import Lexeme, LexemeInflectionPattern, PartOfSpeech, \
-    Vocabulary, Qualifier, ClassificationValue, CrossReference, InputLexeme, \
-    CrossReferenceType, LexemeAttributeValue, Gender, LexemeAttribute, \
-    LexemeAV, LexemeCV, LexemeList
-from dictionary.util import prepare_table
-from patterns.models import Pattern, Ending
 from dictionary.forms import LexemeEditForm, LIPEditForm, ClassificationForm, \
     CrossReferenceForm, ActionFieldForm, ACTION_FIELDS,\
     LexemeOpenAttributeForm, LexemeClosedAttributeForm, \
     LexemeMultipleAttributeForm
-from common.decorators import ajax, AjaxError, render_ajax
-from common.util import error_messages, bisect_left, format_date
+from dictionary.models import Lexeme, LexemeInflectionPattern, PartOfSpeech, \
+    Vocabulary, Qualifier, ClassificationValue, CrossReference, InputLexeme, \
+    CrossReferenceType, LexemeAttributeValue, Gender, LexemeAttribute, \
+    LexemeAV, LexemeCV, LexemeList
+from patterns.models import Ending
 
 
 @render_ajax(
@@ -56,43 +54,6 @@ def inflection_tables(request, variant, lexeme_id):
     }
 
 
-@render_ajax(template='table_preview.html', method='get')
-def table_preview(request, lexeme_id, lip_id, pattern, attr_data=None,
-                  gender=None, entry=None, pos=None):
-    lexeme = Lexeme.all_objects.get(pk=lexeme_id)
-    if not lexeme.perm(request.user, 'view'):
-        raise AjaxError('access denied')
-    if pos is not None:
-        part_of_speech = PartOfSpeech.objects.get(symbol=pos)
-    else:
-        part_of_speech = lexeme.part_of_speech
-    try:
-        if entry is not None:
-            lexeme.entry = entry
-        pattern = Pattern.objects.get(name=pattern)
-        gender = Gender.objects.get(id=gender) if gender else None
-        if attr_data:
-            attr_vals = LexemeAttributeValue.objects.filter(
-                id__in=attr_data)
-        else:
-            attr_vals = None
-        if lip_id.startswith('lip_add'):
-            lip = LexemeInflectionPattern(lexeme=lexeme, index=0)
-        else:
-            lip = LexemeInflectionPattern.objects.get(pk=int(lip_id[3:]))
-        lip.pattern = pattern
-        lip.gender = gender
-        lip.root = lip.get_root()
-        qualifiers = Qualifier.visible_qualifiers(request.user)
-        table = lip.inflection_table(
-            '0', separated=True, qualifiers=qualifiers, edit_view=True,
-            attr_vals=attr_vals, pos=part_of_speech)
-        prepare_table(table)
-    except Pattern.DoesNotExist:
-        table = None
-    return {'table': table, 'color_scheme': part_of_speech.color_scheme}
-
-
 @ajax(template='odm_forms.html', method='get')
 def odm_forms(request, lexeme_id):
     to_return = {}
diff --git a/dictionary/models.py b/dictionary/models.py
index 219ebfe..cdb31f4 100644
--- a/dictionary/models.py
+++ b/dictionary/models.py
@@ -12,7 +12,7 @@ from django.utils.translation import ugettext_lazy as _, get_language
 from accounts.util import users_with_perm
 from common.models import NotDeletedManager
 from common.util import no_history
-from dictionary.util import prepare_table
+from tables.util import prepare_table
 from patterns.models import InflectionType, BaseFormLabel, PatternType, Pattern
 
 
diff --git a/dictionary/urls.py b/dictionary/urls.py
index 9327284..a34d046 100644
--- a/dictionary/urls.py
+++ b/dictionary/urls.py
@@ -25,7 +25,6 @@ urlpatterns += patterns(
     url(r'^ajax/odm-forms/$', 'odm_forms'),
     url(r'^ajax/lexeme-edit-form/$', 'lexeme_edit_form'),
     url(r'^ajax/update-lexeme/$', 'update_lexeme'),
-    url(r'^ajax/table-preview/$', 'table_preview'),
     url(r'^ajax/new-lip-row/$', 'new_lip_edit_row'),
     url(r'^ajax/new-cr-row/$', 'new_cross_reference_row'),
     url(r'^ajax/delete-lexeme/$', 'delete_lexeme'),
diff --git a/dictionary/util.py b/dictionary/util.py
index 4fb560e..8042d73 100644
--- a/dictionary/util.py
+++ b/dictionary/util.py
@@ -58,36 +58,3 @@ def check_query_params(request, query_params):
     reader = query_params.get('reader', True)
     if not request.user.is_authenticated() and not reader:
         raise AjaxError('access denied')
-
-
-def prepare_table(table):
-    for row in table:
-        for cell in row:
-            if type(cell) == dict and 'forms' in cell:
-                cell['forms'].sort()
-                seen_forms = []
-                unique_forms = []
-                form_patterns = {}
-                for form in cell['forms']:
-                    if form[1] not in seen_forms:
-                        seen_forms.append(form[1])
-                        unique_forms.append(form)
-                        form_patterns[form[1]] = set()
-                    form_patterns[form[1]].add(form[3])
-                cell['forms'] = [
-                    {
-                        'form': form,
-                        'qualifiers': qualifiers,
-                        'patterns': form_patterns[form],
-                    }
-                    for (key, form, qualifiers, pattern) in unique_forms]
-            elif type(cell) == dict and 'label' in cell:
-                seen_labels = []
-
-                def is_new(label):
-                    new = label not in seen_labels
-                    seen_labels.append(label)
-                    return new
-
-                cell['label'] = filter(is_new, cell['label'])
-    return table
\ No newline at end of file
diff --git a/settings.py b/settings.py
index a70e470..047bfc1 100644
--- a/settings.py
+++ b/settings.py
@@ -123,6 +123,7 @@ INSTALLED_APPS = (
     # aplikacje projektu
     'dictionary',
     'patterns',
+    'tables',
     'management',
     'export',
     'accounts',
diff --git a/tables/__init__.py b/tables/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tables/__init__.py
diff --git a/tables/management/__init__.py b/tables/management/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tables/management/__init__.py
diff --git a/tables/management/commands/__init__.py b/tables/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tables/management/commands/__init__.py
diff --git a/dictionary/management/commands/export_template.py b/tables/management/commands/export_template.py
index b7de638..b7de638 100644
--- a/dictionary/management/commands/export_template.py
+++ b/tables/management/commands/export_template.py
diff --git a/dictionary/management/commands/export_templates.py b/tables/management/commands/export_templates.py
index e8a2304..cf82ac4 100644
--- a/dictionary/management/commands/export_templates.py
+++ b/tables/management/commands/export_templates.py
@@ -1,8 +1,9 @@
 # -*- coding: utf-8 -*-
 from django.core.management.base import BaseCommand
+
 from common.util import uniprint, json_encode
-from dictionary.management.commands.export_template import export_template
 from dictionary.models import TableTemplate
+from tables.management.commands.export_template import export_template
 
 
 class Command(BaseCommand):
diff --git a/dictionary/management/commands/import_template.py b/tables/management/commands/import_template.py
index 4d1cd84..4d1cd84 100644
--- a/dictionary/management/commands/import_template.py
+++ b/tables/management/commands/import_template.py
diff --git a/dictionary/management/commands/import_templates.py b/tables/management/commands/import_templates.py
index 7b19235..6be9c5c 100644
--- a/dictionary/management/commands/import_templates.py
+++ b/tables/management/commands/import_templates.py
@@ -1,10 +1,12 @@
 # -*- coding: utf-8 -*-
 import json
+
 from django.core.management.base import BaseCommand
-from dictionary.management.commands.import_template import import_template
+
 from dictionary.models import TableTemplate, LexemeAttribute, \
     LexemeAttributeValue
 from patterns.models import PatternType
+from tables.management.commands.import_template import import_template
 
 
 class Command(BaseCommand):
diff --git a/tables/migrations/__init__.py b/tables/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tables/migrations/__init__.py
diff --git a/tables/models.py b/tables/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/tables/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/dictionary/templates/inflection_table.html b/tables/templates/inflection_table.html
index d906672..d906672 100644
--- a/dictionary/templates/inflection_table.html
+++ b/tables/templates/inflection_table.html
diff --git a/management/templates/table_preview.html b/tables/templates/table_preview.html
index 25288eb..25288eb 100644
--- a/management/templates/table_preview.html
+++ b/tables/templates/table_preview.html
diff --git a/tables/tests.py b/tables/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/tables/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/tables/urls.py b/tables/urls.py
new file mode 100644
index 0000000..d506bdf
--- /dev/null
+++ b/tables/urls.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+from django.conf.urls import patterns
+from common.util import url
+
+
+urlpatterns = patterns(
+    'tables.views',
+    url(r'^ajax/table-preview/$', 'table_preview'),
+)
\ No newline at end of file
diff --git a/tables/util.py b/tables/util.py
new file mode 100644
index 0000000..9804dca
--- /dev/null
+++ b/tables/util.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+
+def prepare_table(table):
+    for row in table:
+        for cell in row:
+            if type(cell) == dict and 'forms' in cell:
+                cell['forms'].sort()
+                seen_forms = []
+                unique_forms = []
+                form_patterns = {}
+                for form in cell['forms']:
+                    if form[1] not in seen_forms:
+                        seen_forms.append(form[1])
+                        unique_forms.append(form)
+                        form_patterns[form[1]] = set()
+                    form_patterns[form[1]].add(form[3])
+                cell['forms'] = [
+                    {
+                        'form': form,
+                        'qualifiers': qualifiers,
+                        'patterns': form_patterns[form],
+                    }
+                    for (key, form, qualifiers, pattern) in unique_forms]
+            elif type(cell) == dict and 'label' in cell:
+                seen_labels = []
+
+                def is_new(label):
+                    new = label not in seen_labels
+                    seen_labels.append(label)
+                    return new
+
+                cell['label'] = filter(is_new, cell['label'])
+    return table
diff --git a/tables/views.py b/tables/views.py
new file mode 100644
index 0000000..81671bf
--- /dev/null
+++ b/tables/views.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+from django.shortcuts import render
+
+from common.decorators import render_ajax, AjaxError
+from dictionary.models import Lexeme, PartOfSpeech, Gender, \
+    LexemeAttributeValue, LexemeInflectionPattern, Qualifier
+from tables.util import prepare_table
+from patterns.models import Pattern
+
+
+@render_ajax(template='table_preview.html', method='get')
+def table_preview(request, lexeme_id, lip_id, pattern, attr_data=None,
+                  gender=None, entry=None, pos=None):
+    lexeme = Lexeme.all_objects.get(pk=lexeme_id)
+    if not lexeme.perm(request.user, 'view'):
+        raise AjaxError('access denied')
+    if pos is not None:
+        part_of_speech = PartOfSpeech.objects.get(symbol=pos)
+    else:
+        part_of_speech = lexeme.part_of_speech
+    try:
+        if entry is not None:
+            lexeme.entry = entry
+        pattern = Pattern.objects.get(name=pattern)
+        gender = Gender.objects.get(id=gender) if gender else None
+        if attr_data:
+            attr_vals = LexemeAttributeValue.objects.filter(
+                id__in=attr_data)
+        else:
+            attr_vals = None
+        if lip_id.startswith('lip_add'):
+            lip = LexemeInflectionPattern(lexeme=lexeme, index=0)
+        else:
+            lip = LexemeInflectionPattern.objects.get(pk=int(lip_id[3:]))
+        lip.pattern = pattern
+        lip.gender = gender
+        lip.root = lip.get_root()
+        qualifiers = Qualifier.visible_qualifiers(request.user)
+        table = lip.inflection_table(
+            '0', separated=True, qualifiers=qualifiers, edit_view=True,
+            attr_vals=attr_vals, pos=part_of_speech)
+        prepare_table(table)
+    except Pattern.DoesNotExist:
+        table = None
+    return {'table': table, 'color_scheme': part_of_speech.color_scheme}
\ No newline at end of file
diff --git a/urls.py b/urls.py
index 8e4ac83..8e07901 100644
--- a/urls.py
+++ b/urls.py
@@ -36,4 +36,5 @@ urlpatterns = patterns(
     (r'^paginer/', include('paginer.urls')),
     (r'^historia/', include('history.urls')),
     (r'^eksport/', include('export.urls')),
+    (r'^tables/', include('tables.urls')),
 )