django/tests/modeltests/schema/tests.py

175 lines
5.7 KiB
Python
Raw Normal View History

from __future__ import absolute_import
import copy
import datetime
from django.test import TestCase
from django.db import connection, DatabaseError, IntegrityError
from django.db.models.fields import IntegerField, TextField
from django.db.models.loading import cache
from .models import Author, Book
class SchemaTests(TestCase):
"""
Tests that the schema-alteration code works correctly.
Be aware that these tests are more liable than most to false results,
as sometimes the code to check if a test has worked is almost as complex
as the code it is testing.
"""
models = [Author, Book]
# Utility functions
def setUp(self):
# Make sure we're in manual transaction mode
connection.commit_unless_managed()
connection.enter_transaction_management()
connection.managed(True)
# The unmanaged models need to be removed after the test in order to
# prevent bad interactions with the flush operation in other tests.
self.old_app_models = copy.deepcopy(cache.app_models)
self.old_app_store = copy.deepcopy(cache.app_store)
for model in self.models:
model._meta.managed = True
def tearDown(self):
# Rollback anything that may have happened
connection.rollback()
# Delete any tables made for our models
cursor = connection.cursor()
for model in self.models:
try:
cursor.execute("DROP TABLE %s CASCADE" % (
connection.ops.quote_name(model._meta.db_table),
))
except DatabaseError:
connection.rollback()
else:
connection.commit()
# Unhook our models
for model in self.models:
model._meta.managed = False
cache.app_models = self.old_app_models
cache.app_store = self.old_app_store
cache._get_models_cache = {}
def column_classes(self, model):
cursor = connection.cursor()
return dict(
(d[0], (connection.introspection.get_field_type(d[1], d), d))
for d in connection.introspection.get_table_description(
cursor,
model._meta.db_table,
)
)
# Tests
def test_creation_deletion(self):
"""
Tries creating a model's table, and then deleting it.
"""
# Create the table
editor = connection.schema_editor()
editor.start()
editor.create_model(Author)
editor.commit()
# Check that it's there
try:
list(Author.objects.all())
except DatabaseError, e:
self.fail("Table not created: %s" % e)
# Clean up that table
editor.start()
editor.delete_model(Author)
editor.commit()
# Check that it's gone
self.assertRaises(
DatabaseError,
lambda: list(Author.objects.all()),
)
def test_creation_fk(self):
"Tests that creating tables out of FK order works"
# Create the table
editor = connection.schema_editor()
editor.start()
editor.create_model(Book)
editor.create_model(Author)
editor.commit()
# Check that both tables are there
try:
list(Author.objects.all())
except DatabaseError, e:
self.fail("Author table not created: %s" % e)
try:
list(Book.objects.all())
except DatabaseError, e:
self.fail("Book table not created: %s" % e)
# Make sure the FK constraint is present
with self.assertRaises(IntegrityError):
Book.objects.create(
author_id = 1,
title = "Much Ado About Foreign Keys",
pub_date = datetime.datetime.now(),
)
connection.commit()
def test_create_field(self):
"""
Tests adding fields to models
"""
# Create the table
editor = connection.schema_editor()
editor.start()
editor.create_model(Author)
editor.commit()
# Ensure there's no age field
columns = self.column_classes(Author)
self.assertNotIn("age", columns)
# Alter the name field to a TextField
new_field = IntegerField(null=True)
new_field.set_attributes_from_name("age")
editor = connection.schema_editor()
editor.start()
editor.create_field(
Author,
new_field,
)
editor.commit()
# Ensure the field is right afterwards
columns = self.column_classes(Author)
self.assertEqual(columns['age'][0], "IntegerField")
self.assertEqual(columns['age'][1][6], True)
def test_alter(self):
"""
Tests simple altering of fields
"""
# Create the table
editor = connection.schema_editor()
editor.start()
editor.create_model(Author)
editor.commit()
# Ensure the field is right to begin with
columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "CharField")
self.assertEqual(columns['name'][1][3], 255)
self.assertEqual(columns['name'][1][6], False)
# Alter the name field to a TextField
new_field = TextField(null=True)
new_field.set_attributes_from_name("name")
editor = connection.schema_editor()
editor.start()
editor.alter_field(
Author,
Author._meta.get_field_by_name("name")[0],
new_field,
)
editor.commit()
# Ensure the field is right afterwards
columns = self.column_classes(Author)
self.assertEqual(columns['name'][0], "TextField")
self.assertEqual(columns['name'][1][6], True)