django1/tests/fixtures_regress/tests.py

931 lines
32 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# Unittests for fixtures.
from __future__ import unicode_literals
import json
import os
import re
import unittest
2013-05-19 18:49:03 +08:00
import warnings
import django
from django.core import management, serializers
from django.core.exceptions import ImproperlyConfigured
from django.core.serializers.base import DeserializationError
from django.db import IntegrityError, transaction
from django.db.models import signals
from django.test import (
TestCase, TransactionTestCase, override_settings, skipIfDBFeature,
skipUnlessDBFeature,
)
from django.utils import six
from django.utils._os import upath
from django.utils.six import PY3, StringIO
from .models import (
Absolute, Animal, Article, Book, Child, Circle1, Circle2, Circle3,
ExternalDependency, M2MCircular1ThroughAB, M2MCircular1ThroughBC,
M2MCircular1ThroughCA, M2MCircular2ThroughAB, M2MComplexA, M2MComplexB,
M2MComplexCircular1A, M2MComplexCircular1B, M2MComplexCircular1C,
M2MComplexCircular2A, M2MComplexCircular2B, M2MSimpleA, M2MSimpleB,
M2MSimpleCircularA, M2MSimpleCircularB, M2MThroughAB, NKChild, Parent,
Person, RefToNKChild, Store, Stuff, Thingy, Widget,
)
_cur_dir = os.path.dirname(os.path.abspath(upath(__file__)))
def is_ascii(s):
return all(ord(c) < 128 for c in s)
skipIfNonASCIIPath = unittest.skipIf(
not is_ascii(django.__file__) and six.PY2,
'Python 2 crashes when checking non-ASCII exception messages.'
)
class TestFixtures(TestCase):
def animal_pre_save_check(self, signal, sender, instance, **kwargs):
self.pre_save_checks.append(
(
'Count = %s (%s)' % (instance.count, type(instance.count)),
'Weight = %s (%s)' % (instance.weight, type(instance.weight)),
)
)
def test_duplicate_pk(self):
"""
This is a regression test for ticket #3790.
"""
# Load a fixture that uses PK=1
management.call_command(
'loaddata',
'sequence',
verbosity=0,
)
# Create a new animal. Without a sequence reset, this new object
# will take a PK of 1 (on Postgres), and the save will fail.
animal = Animal(
name='Platypus',
latin_name='Ornithorhynchus anatinus',
count=2,
weight=2.2,
)
animal.save()
self.assertGreater(animal.id, 1)
def test_loaddata_not_found_fields_not_ignore(self):
"""
Test for ticket #9279 -- Error is raised for entries in
the serialized data for fields that have been removed
from the database when not ignored.
"""
with self.assertRaises(DeserializationError):
management.call_command(
'loaddata',
'sequence_extra',
verbosity=0,
)
def test_loaddata_not_found_fields_ignore(self):
"""
Test for ticket #9279 -- Ignores entries in
the serialized data for fields that have been removed
from the database.
"""
management.call_command(
'loaddata',
'sequence_extra',
ignore=True,
verbosity=0,
)
self.assertEqual(Animal.specimens.all()[0].name, 'Lion')
def test_loaddata_not_found_fields_ignore_xml(self):
"""
Test for ticket #19998 -- Ignore entries in the XML serialized data
for fields that have been removed from the model definition.
"""
management.call_command(
'loaddata',
'sequence_extra_xml',
ignore=True,
verbosity=0,
)
self.assertEqual(Animal.specimens.all()[0].name, 'Wolf')
@skipIfDBFeature('interprets_empty_strings_as_nulls')
def test_pretty_print_xml(self):
"""
Regression test for ticket #4558 -- pretty printing of XML fixtures
doesn't affect parsing of None values.
"""
# Load a pretty-printed XML fixture with Nulls.
management.call_command(
'loaddata',
'pretty.xml',
verbosity=0,
)
self.assertIsNone(Stuff.objects.all()[0].name)
self.assertIsNone(Stuff.objects.all()[0].owner)
@skipUnlessDBFeature('interprets_empty_strings_as_nulls')
def test_pretty_print_xml_empty_strings(self):
"""
Regression test for ticket #4558 -- pretty printing of XML fixtures
doesn't affect parsing of None values.
"""
# Load a pretty-printed XML fixture with Nulls.
management.call_command(
'loaddata',
'pretty.xml',
verbosity=0,
)
self.assertEqual(Stuff.objects.all()[0].name, '')
self.assertIsNone(Stuff.objects.all()[0].owner)
def test_absolute_path(self):
"""
Regression test for ticket #6436 --
os.path.join will throw away the initial parts of a path if it
encounters an absolute path.
This means that if a fixture is specified as an absolute path,
we need to make sure we don't discover the absolute path in every
fixture directory.
"""
load_absolute_path = os.path.join(
os.path.dirname(upath(__file__)),
'fixtures',
'absolute.json'
)
management.call_command(
'loaddata',
load_absolute_path,
verbosity=0,
)
self.assertEqual(Absolute.objects.count(), 1)
def test_relative_path(self, path=['fixtures', 'absolute.json']):
relative_path = os.path.join(*path)
cwd = os.getcwd()
try:
os.chdir(_cur_dir)
management.call_command(
'loaddata',
relative_path,
verbosity=0,
)
finally:
os.chdir(cwd)
self.assertEqual(Absolute.objects.count(), 1)
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1')])
def test_relative_path_in_fixture_dirs(self):
self.test_relative_path(path=['inner', 'absolute.json'])
def test_path_containing_dots(self):
management.call_command(
'loaddata',
'path.containing.dots.json',
verbosity=0,
)
self.assertEqual(Absolute.objects.count(), 1)
def test_unknown_format(self):
"""
Test for ticket #4371 -- Loading data of an unknown format should fail
Validate that error conditions are caught correctly
"""
msg = "Problem installing fixture 'bad_fixture1': unkn is not a known serialization format."
with self.assertRaisesMessage(management.CommandError, msg):
management.call_command(
'loaddata',
'bad_fixture1.unkn',
verbosity=0,
)
@skipIfNonASCIIPath
@override_settings(SERIALIZATION_MODULES={'unkn': 'unexistent.path'})
def test_unimportable_serializer(self):
"""
Test that failing serializer import raises the proper error
"""
2016-04-08 10:04:45 +08:00
with six.assertRaisesRegex(self, ImportError, r"No module named.*unexistent"):
management.call_command(
'loaddata',
'bad_fixture1.unkn',
verbosity=0,
)
def test_invalid_data(self):
"""
Test for ticket #4371 -- Loading a fixture file with invalid data
using explicit filename.
Test for ticket #18213 -- warning conditions are caught correctly
"""
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")
management.call_command(
'loaddata',
'bad_fixture2.xml',
verbosity=0,
)
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_invalid_data_no_ext(self):
"""
Test for ticket #4371 -- Loading a fixture file with invalid data
without file extension.
Test for ticket #18213 -- warning conditions are caught correctly
"""
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")
management.call_command(
'loaddata',
'bad_fixture2',
verbosity=0,
)
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_empty(self):
"""
Test for ticket #18213 -- Loading a fixture file with no data output a warning.
Previously empty fixture raises an error exception, see ticket #4371.
"""
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")
management.call_command(
'loaddata',
'empty',
verbosity=0,
)
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
2016-04-08 10:04:45 +08:00
self.assertEqual(str(warning.message), "No fixture data found for 'empty'. (File format may be invalid.)")
def test_error_message(self):
"""
Regression for #9011 - error message is correct.
Change from error to warning for ticket #18213.
"""
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always")
management.call_command(
'loaddata',
'bad_fixture2',
'animal',
verbosity=0,
)
warning = warning_list.pop()
self.assertEqual(warning.category, RuntimeWarning)
self.assertEqual(
str(warning.message),
"No fixture data found for 'bad_fixture2'. (File format may be invalid.)"
)
def test_pg_sequence_resetting_checks(self):
"""
Test for ticket #7565 -- PostgreSQL sequence resetting checks shouldn't
ascend to parent models when inheritance is used
(since they are treated individually).
"""
management.call_command(
'loaddata',
'model-inheritance.json',
verbosity=0,
)
self.assertEqual(Parent.objects.all()[0].id, 1)
self.assertEqual(Child.objects.all()[0].id, 1)
def test_close_connection_after_loaddata(self):
"""
Test for ticket #7572 -- MySQL has a problem if the same connection is
used to create tables, load data, and then query over that data.
To compensate, we close the connection after running loaddata.
This ensures that a new connection is opened when test queries are
issued.
"""
management.call_command(
'loaddata',
'big-fixture.json',
verbosity=0,
)
articles = Article.objects.exclude(id=9)
self.assertEqual(
list(articles.values_list('id', flat=True)),
[1, 2, 3, 4, 5, 6, 7, 8]
)
# Just for good measure, run the same query again.
# Under the influence of ticket #7572, this will
# give a different result to the previous call.
self.assertEqual(
list(articles.values_list('id', flat=True)),
[1, 2, 3, 4, 5, 6, 7, 8]
)
def test_field_value_coerce(self):
"""
Test for tickets #8298, #9942 - Field values should be coerced into the
correct type by the deserializer, not as part of the database write.
"""
self.pre_save_checks = []
signals.pre_save.connect(self.animal_pre_save_check)
try:
management.call_command(
'loaddata',
'animal.xml',
verbosity=0,
)
self.assertEqual(
self.pre_save_checks,
[
("Count = 42 (<%s 'int'>)" % ('class' if PY3 else 'type'),
"Weight = 1.2 (<%s 'float'>)" % ('class' if PY3 else 'type'))
]
)
finally:
signals.pre_save.disconnect(self.animal_pre_save_check)
def test_dumpdata_uses_default_manager(self):
"""
Regression for #11286
Ensure that dumpdata honors the default manager
Dump the current contents of the database as a JSON fixture
"""
management.call_command(
'loaddata',
'animal.xml',
verbosity=0,
)
management.call_command(
'loaddata',
'sequence.json',
verbosity=0,
)
animal = Animal(
name='Platypus',
latin_name='Ornithorhynchus anatinus',
count=2,
weight=2.2,
)
animal.save()
out = StringIO()
management.call_command(
'dumpdata',
'fixtures_regress.animal',
format='json',
stdout=out,
)
# Output order isn't guaranteed, so check for parts
data = out.getvalue()
# Get rid of artifacts like '000000002' to eliminate the differences
# between different Python versions.
data = re.sub('0{6,}[0-9]', '', data)
animals_data = sorted([
{
"pk": 1, "model": "fixtures_regress.animal",
"fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}
},
{
"pk": 10, "model": "fixtures_regress.animal",
"fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}
},
{
"pk": animal.pk, "model": "fixtures_regress.animal",
"fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}
},
], key=lambda x: x["pk"])
data = sorted(json.loads(data), key=lambda x: x["pk"])
self.maxDiff = 1024
self.assertEqual(data, animals_data)
def test_proxy_model_included(self):
"""
Regression for #11428 - Proxy models aren't included when you dumpdata
"""
out = StringIO()
# Create an instance of the concrete class
widget = Widget.objects.create(name='grommet')
management.call_command(
'dumpdata',
'fixtures_regress.widget',
'fixtures_regress.widgetproxy',
format='json',
stdout=out,
)
self.assertJSONEqual(
out.getvalue(),
"""[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]"""
% widget.pk
)
@skipUnlessDBFeature('supports_forward_references')
def test_loaddata_works_when_fixture_has_forward_refs(self):
"""
Regression for #3615 - Forward references cause fixtures not to load in MySQL (InnoDB)
"""
management.call_command(
'loaddata',
'forward_ref.json',
verbosity=0,
)
self.assertEqual(Book.objects.all()[0].id, 1)
self.assertEqual(Person.objects.all()[0].id, 4)
def test_loaddata_raises_error_when_fixture_has_invalid_foreign_key(self):
"""
Regression for #3615 - Ensure data with nonexistent child key references raises error
"""
with self.assertRaisesMessage(IntegrityError, "Problem installing fixture"):
management.call_command(
'loaddata',
'forward_ref_bad_data.json',
verbosity=0,
)
@skipUnlessDBFeature('supports_forward_references')
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
os.path.join(_cur_dir, 'fixtures_2')])
def test_loaddata_forward_refs_split_fixtures(self):
"""
Regression for #17530 - should be able to cope with forward references
when the fixtures are not in the same files or directories.
"""
management.call_command(
'loaddata',
'forward_ref_1.json',
'forward_ref_2.json',
verbosity=0,
)
self.assertEqual(Book.objects.all()[0].id, 1)
self.assertEqual(Person.objects.all()[0].id, 4)
def test_loaddata_no_fixture_specified(self):
"""
Regression for #7043 - Error is quickly reported when no fixtures is provided in the command line.
"""
msg = "No database fixture specified. Please provide the path of at least one fixture in the command line."
with self.assertRaisesMessage(management.CommandError, msg):
management.call_command(
'loaddata',
verbosity=0,
)
def test_ticket_20820(self):
"""
Regression for ticket #20820 -- loaddata on a model that inherits
from a model with a M2M shouldn't blow up.
"""
management.call_command(
'loaddata',
'special-article.json',
verbosity=0,
)
def test_ticket_22421(self):
"""
Regression for ticket #22421 -- loaddata on a model that inherits from
a grand-parent model with a M2M but via an abstract parent shouldn't
blow up.
"""
management.call_command(
'loaddata',
'feature.json',
verbosity=0,
)
def test_loaddata_with_m2m_to_self(self):
"""
Regression test for ticket #17946.
"""
management.call_command(
'loaddata',
'm2mtoself.json',
verbosity=0,
)
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
os.path.join(_cur_dir, 'fixtures_1')])
def test_fixture_dirs_with_duplicates(self):
"""
settings.FIXTURE_DIRS cannot contain duplicates in order to avoid
repeated fixture loading.
"""
with self.assertRaisesMessage(ImproperlyConfigured, "settings.FIXTURE_DIRS contains duplicates."):
management.call_command('loaddata', 'absolute.json', verbosity=0)
@skipIfNonASCIIPath
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures')])
def test_fixture_dirs_with_default_fixture_path(self):
"""
settings.FIXTURE_DIRS cannot contain a default fixtures directory
for application (app/fixtures) in order to avoid repeated fixture loading.
"""
msg = (
"'%s' is a default fixture directory for the '%s' app "
"and cannot be listed in settings.FIXTURE_DIRS."
% (os.path.join(_cur_dir, 'fixtures'), 'fixtures_regress')
)
with self.assertRaisesMessage(ImproperlyConfigured, msg):
management.call_command('loaddata', 'absolute.json', verbosity=0)
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
os.path.join(_cur_dir, 'fixtures_2')])
def test_loaddata_with_valid_fixture_dirs(self):
management.call_command(
'loaddata',
'absolute.json',
verbosity=0,
)
class NaturalKeyFixtureTests(TestCase):
def test_nk_deserialize(self):
"""
Test for ticket #13030 - Python based parser version
natural keys deserialize with fk to inheriting model
"""
management.call_command(
'loaddata',
'model-inheritance.json',
verbosity=0,
)
management.call_command(
'loaddata',
'nk-inheritance.json',
verbosity=0,
)
self.assertEqual(
NKChild.objects.get(pk=1).data,
'apple'
)
self.assertEqual(
RefToNKChild.objects.get(pk=1).nk_fk.data,
'apple'
)
def test_nk_deserialize_xml(self):
"""
Test for ticket #13030 - XML version
natural keys deserialize with fk to inheriting model
"""
management.call_command(
'loaddata',
'model-inheritance.json',
verbosity=0,
)
management.call_command(
'loaddata',
'nk-inheritance.json',
verbosity=0,
)
management.call_command(
'loaddata',
'nk-inheritance2.xml',
verbosity=0,
)
self.assertEqual(
NKChild.objects.get(pk=2).data,
'banana'
)
self.assertEqual(
RefToNKChild.objects.get(pk=2).nk_fk.data,
'apple'
)
def test_nk_on_serialize(self):
"""
Check that natural key requirements are taken into account
when serializing models
"""
management.call_command(
'loaddata',
'forward_ref_lookup.json',
verbosity=0,
)
out = StringIO()
management.call_command(
'dumpdata',
'fixtures_regress.book',
'fixtures_regress.person',
'fixtures_regress.store',
verbosity=0,
format='json',
use_natural_foreign_keys=True,
use_natural_primary_keys=True,
stdout=out,
)
self.assertJSONEqual(
out.getvalue(),
"""
[{"fields": {"main": null, "name": "Amazon"}, "model": "fixtures_regress.store"},
{"fields": {"main": null, "name": "Borders"}, "model": "fixtures_regress.store"},
{"fields": {"name": "Neal Stephenson"}, "model": "fixtures_regress.person"},
{"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]],
"name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]
"""
)
def test_dependency_sorting(self):
"""
Now lets check the dependency sorting explicitly
It doesn't matter what order you mention the models
Store *must* be serialized before then Person, and both
must be serialized before Book.
"""
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Book, Person, Store])]
)
self.assertEqual(
sorted_deps,
[Store, Person, Book]
)
def test_dependency_sorting_2(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Book, Store, Person])]
)
self.assertEqual(
sorted_deps,
[Store, Person, Book]
)
def test_dependency_sorting_3(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Store, Book, Person])]
)
self.assertEqual(
sorted_deps,
[Store, Person, Book]
)
def test_dependency_sorting_4(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Store, Person, Book])]
)
self.assertEqual(
sorted_deps,
[Store, Person, Book]
)
def test_dependency_sorting_5(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Person, Book, Store])]
)
self.assertEqual(
sorted_deps,
[Store, Person, Book]
)
def test_dependency_sorting_6(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Person, Store, Book])]
)
self.assertEqual(
sorted_deps,
[Store, Person, Book]
)
def test_dependency_sorting_dangling(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Person, Circle1, Store, Book])]
)
self.assertEqual(
sorted_deps,
[Circle1, Store, Person, Book]
)
def test_dependency_sorting_tight_circular(self):
with self.assertRaisesMessage(
RuntimeError,
"Can't resolve dependencies for fixtures_regress.Circle1, "
"fixtures_regress.Circle2 in serialized app list."
):
serializers.sort_dependencies([('fixtures_regress', [Person, Circle2, Circle1, Store, Book])])
def test_dependency_sorting_tight_circular_2(self):
with self.assertRaisesMessage(
RuntimeError,
"Can't resolve dependencies for fixtures_regress.Circle1, "
"fixtures_regress.Circle2 in serialized app list."
):
serializers.sort_dependencies([('fixtures_regress', [Circle1, Book, Circle2])])
def test_dependency_self_referential(self):
with self.assertRaisesMessage(
RuntimeError,
"Can't resolve dependencies for fixtures_regress.Circle3 in "
"serialized app list."
):
serializers.sort_dependencies([('fixtures_regress', [Book, Circle3])])
def test_dependency_sorting_long(self):
with self.assertRaisesMessage(
RuntimeError,
"Can't resolve dependencies for fixtures_regress.Circle1, "
"fixtures_regress.Circle2, fixtures_regress.Circle3 in serialized "
"app list."
):
serializers.sort_dependencies([('fixtures_regress', [Person, Circle2, Circle1, Circle3, Store, Book])])
def test_dependency_sorting_normal(self):
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [Person, ExternalDependency, Book])]
)
self.assertEqual(
sorted_deps,
[Person, Book, ExternalDependency]
)
def test_normal_pk(self):
"""
Check that normal primary keys still work
on a model with natural key capabilities
"""
management.call_command(
'loaddata',
'non_natural_1.json',
verbosity=0,
)
management.call_command(
'loaddata',
'forward_ref_lookup.json',
verbosity=0,
)
management.call_command(
'loaddata',
'non_natural_2.xml',
verbosity=0,
)
books = Book.objects.all()
self.assertQuerysetEqual(
books, [
"<Book: Cryptonomicon by Neal Stephenson (available at Amazon, Borders)>",
"<Book: Ender's Game by Orson Scott Card (available at Collins Bookstore)>",
"<Book: Permutation City by Greg Egan (available at Angus and Robertson)>",
]
)
class M2MNaturalKeyFixtureTests(TestCase):
"""Tests for ticket #14426."""
def test_dependency_sorting_m2m_simple(self):
"""
M2M relations without explicit through models SHOULD count as dependencies
Regression test for bugs that could be caused by flawed fixes to
#14226, namely if M2M checks are removed from sort_dependencies
altogether.
"""
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [M2MSimpleA, M2MSimpleB])]
)
self.assertEqual(sorted_deps, [M2MSimpleB, M2MSimpleA])
def test_dependency_sorting_m2m_simple_circular(self):
"""
Resolving circular M2M relations without explicit through models should
fail loudly
"""
with self.assertRaisesMessage(
RuntimeError,
"Can't resolve dependencies for fixtures_regress.M2MSimpleCircularA, "
"fixtures_regress.M2MSimpleCircularB in serialized app list."
):
serializers.sort_dependencies([('fixtures_regress', [M2MSimpleCircularA, M2MSimpleCircularB])])
def test_dependency_sorting_m2m_complex(self):
"""
M2M relations with explicit through models should NOT count as
dependencies. The through model itself will have dependencies, though.
"""
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [M2MComplexA, M2MComplexB, M2MThroughAB])]
)
# Order between M2MComplexA and M2MComplexB doesn't matter. The through
# model has dependencies to them though, so it should come last.
self.assertEqual(sorted_deps[-1], M2MThroughAB)
def test_dependency_sorting_m2m_complex_circular_1(self):
"""
Circular M2M relations with explicit through models should be serializable
"""
A, B, C, AtoB, BtoC, CtoA = (M2MComplexCircular1A, M2MComplexCircular1B,
M2MComplexCircular1C, M2MCircular1ThroughAB,
M2MCircular1ThroughBC, M2MCircular1ThroughCA)
sorted_deps = serializers.sort_dependencies(
[('fixtures_regress', [A, B, C, AtoB, BtoC, CtoA])]
)
# The dependency sorting should not result in an error, and the
# through model should have dependencies to the other models and as
# such come last in the list.
self.assertEqual(sorted_deps[:3], [A, B, C])
self.assertEqual(sorted_deps[3:], [AtoB, BtoC, CtoA])
def test_dependency_sorting_m2m_complex_circular_2(self):
"""
Circular M2M relations with explicit through models should be serializable
This test tests the circularity with explicit natural_key.dependencies
"""
sorted_deps = serializers.sort_dependencies([
('fixtures_regress', [M2MComplexCircular2A, M2MComplexCircular2B, M2MCircular2ThroughAB])
])
self.assertEqual(sorted_deps[:2], [M2MComplexCircular2A, M2MComplexCircular2B])
self.assertEqual(sorted_deps[2:], [M2MCircular2ThroughAB])
def test_dump_and_load_m2m_simple(self):
"""
Test serializing and deserializing back models with simple M2M relations
"""
a = M2MSimpleA.objects.create(data="a")
b1 = M2MSimpleB.objects.create(data="b1")
b2 = M2MSimpleB.objects.create(data="b2")
a.b_set.add(b1)
a.b_set.add(b2)
out = StringIO()
management.call_command(
'dumpdata',
'fixtures_regress.M2MSimpleA',
'fixtures_regress.M2MSimpleB',
use_natural_foreign_keys=True,
stdout=out,
)
for model in [M2MSimpleA, M2MSimpleB]:
model.objects.all().delete()
objects = serializers.deserialize("json", out.getvalue())
for obj in objects:
obj.save()
new_a = M2MSimpleA.objects.get_by_natural_key("a")
self.assertQuerysetEqual(new_a.b_set.all(), [
"<M2MSimpleB: b1>",
"<M2MSimpleB: b2>"
], ordered=False)
class TestTicket11101(TransactionTestCase):
available_apps = [
'fixtures_regress',
'django.contrib.auth',
'django.contrib.contenttypes',
]
@skipUnlessDBFeature('supports_transactions')
def test_ticket_11101(self):
"""Test that fixtures can be rolled back (ticket #11101)."""
with transaction.atomic():
management.call_command(
'loaddata',
'thingy.json',
verbosity=0,
)
self.assertEqual(Thingy.objects.count(), 1)
transaction.set_rollback(True)
self.assertEqual(Thingy.objects.count(), 0)
class TestLoadFixtureFromOtherAppDirectory(TestCase):
"""
#23612 -- fixtures path should be normalized to allow referencing relative
paths on Windows.
"""
current_dir = os.path.abspath(os.path.dirname(__file__))
# relative_prefix is something like tests/fixtures_regress or
# fixtures_regress depending on how runtests.py is invoked.
# All path separators must be / in order to be a proper regression test on
# Windows, so replace as appropriate.
relative_prefix = os.path.relpath(current_dir, os.getcwd()).replace('\\', '/')
fixtures = [relative_prefix + '/fixtures/absolute.json']
def test_fixtures_loaded(self):
count = Absolute.objects.count()
self.assertGreater(count, 0, "Fixtures not loaded properly.")