8 set |
8 set |
9 except NameError: |
9 except NameError: |
10 from sets import Set as set # Python 2.3 fallback |
10 from sets import Set as set # Python 2.3 fallback |
11 |
11 |
12 class Command(BaseCommand): |
12 class Command(BaseCommand): |
13 option_list = BaseCommand.option_list + ( |
|
14 make_option('--verbosity', action='store', dest='verbosity', default='1', |
|
15 type='choice', choices=['0', '1', '2'], |
|
16 help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'), |
|
17 ) |
|
18 help = 'Installs the named fixture(s) in the database.' |
13 help = 'Installs the named fixture(s) in the database.' |
19 args = "fixture [fixture ...]" |
14 args = "fixture [fixture ...]" |
20 |
15 |
21 def handle(self, *fixture_labels, **options): |
16 def handle(self, *fixture_labels, **options): |
22 from django.db.models import get_apps |
17 from django.db.models import get_apps |
27 self.style = no_style() |
22 self.style = no_style() |
28 |
23 |
29 verbosity = int(options.get('verbosity', 1)) |
24 verbosity = int(options.get('verbosity', 1)) |
30 show_traceback = options.get('traceback', False) |
25 show_traceback = options.get('traceback', False) |
31 |
26 |
|
27 # commit is a stealth option - it isn't really useful as |
|
28 # a command line option, but it can be useful when invoking |
|
29 # loaddata from within another script. |
|
30 # If commit=True, loaddata will use its own transaction; |
|
31 # if commit=False, the data load SQL will become part of |
|
32 # the transaction in place when loaddata was invoked. |
|
33 commit = options.get('commit', True) |
|
34 |
32 # Keep a count of the installed objects and fixtures |
35 # Keep a count of the installed objects and fixtures |
33 fixture_count = 0 |
36 fixture_count = 0 |
34 object_count = 0 |
37 object_count = 0 |
|
38 objects_per_fixture = [] |
35 models = set() |
39 models = set() |
36 |
40 |
37 humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path' |
41 humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path' |
38 |
42 |
39 # Get a cursor (even though we don't need one yet). This has |
43 # Get a cursor (even though we don't need one yet). This has |
41 # it isn't already initialized). |
45 # it isn't already initialized). |
42 cursor = connection.cursor() |
46 cursor = connection.cursor() |
43 |
47 |
44 # Start transaction management. All fixtures are installed in a |
48 # Start transaction management. All fixtures are installed in a |
45 # single transaction to ensure that all references are resolved. |
49 # single transaction to ensure that all references are resolved. |
46 transaction.commit_unless_managed() |
50 if commit: |
47 transaction.enter_transaction_management() |
51 transaction.commit_unless_managed() |
48 transaction.managed(True) |
52 transaction.enter_transaction_management() |
|
53 transaction.managed(True) |
49 |
54 |
50 app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()] |
55 app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()] |
51 for fixture_label in fixture_labels: |
56 for fixture_label in fixture_labels: |
52 parts = fixture_label.split('.') |
57 parts = fixture_label.split('.') |
53 if len(parts) == 1: |
58 if len(parts) == 1: |
58 if format in serializers.get_public_serializer_formats(): |
63 if format in serializers.get_public_serializer_formats(): |
59 formats = [format] |
64 formats = [format] |
60 else: |
65 else: |
61 formats = [] |
66 formats = [] |
62 |
67 |
63 if verbosity >= 2: |
68 if formats: |
64 if formats: |
69 if verbosity > 1: |
65 print "Loading '%s' fixtures..." % fixture_name |
70 print "Loading '%s' fixtures..." % fixture_name |
66 else: |
71 else: |
67 print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format) |
72 sys.stderr.write( |
|
73 self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format." % |
|
74 (fixture_name, format))) |
|
75 transaction.rollback() |
|
76 transaction.leave_transaction_management() |
|
77 return |
68 |
78 |
69 if os.path.isabs(fixture_name): |
79 if os.path.isabs(fixture_name): |
70 fixture_dirs = [fixture_name] |
80 fixture_dirs = [fixture_name] |
71 else: |
81 else: |
72 fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + [''] |
82 fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + [''] |
91 transaction.rollback() |
101 transaction.rollback() |
92 transaction.leave_transaction_management() |
102 transaction.leave_transaction_management() |
93 return |
103 return |
94 else: |
104 else: |
95 fixture_count += 1 |
105 fixture_count += 1 |
|
106 objects_per_fixture.append(0) |
96 if verbosity > 0: |
107 if verbosity > 0: |
97 print "Installing %s fixture '%s' from %s." % \ |
108 print "Installing %s fixture '%s' from %s." % \ |
98 (format, fixture_name, humanize(fixture_dir)) |
109 (format, fixture_name, humanize(fixture_dir)) |
99 try: |
110 try: |
100 objects = serializers.deserialize(format, fixture) |
111 objects = serializers.deserialize(format, fixture) |
101 for obj in objects: |
112 for obj in objects: |
102 object_count += 1 |
113 object_count += 1 |
|
114 objects_per_fixture[-1] += 1 |
103 models.add(obj.object.__class__) |
115 models.add(obj.object.__class__) |
104 obj.save() |
116 obj.save() |
105 label_found = True |
117 label_found = True |
106 except Exception, e: |
118 except (SystemExit, KeyboardInterrupt): |
|
119 raise |
|
120 except Exception: |
|
121 import traceback |
107 fixture.close() |
122 fixture.close() |
108 transaction.rollback() |
123 transaction.rollback() |
109 transaction.leave_transaction_management() |
124 transaction.leave_transaction_management() |
110 if show_traceback: |
125 if show_traceback: |
111 import traceback |
126 import traceback |
112 traceback.print_exc() |
127 traceback.print_exc() |
113 else: |
128 else: |
114 sys.stderr.write( |
129 sys.stderr.write( |
115 self.style.ERROR("Problem installing fixture '%s': %s\n" % |
130 self.style.ERROR("Problem installing fixture '%s': %s\n" % |
116 (full_path, str(e)))) |
131 (full_path, traceback.format_exc()))) |
117 return |
132 return |
118 fixture.close() |
133 fixture.close() |
119 except: |
134 except: |
120 if verbosity >= 2: |
135 if verbosity > 1: |
121 print "No %s fixture '%s' in %s." % \ |
136 print "No %s fixture '%s' in %s." % \ |
122 (format, fixture_name, humanize(fixture_dir)) |
137 (format, fixture_name, humanize(fixture_dir)) |
123 |
138 |
|
139 |
|
140 # If any of the fixtures we loaded contain 0 objects, assume that an |
|
141 # error was encountered during fixture loading. |
|
142 if 0 in objects_per_fixture: |
|
143 sys.stderr.write( |
|
144 self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" % |
|
145 (fixture_name))) |
|
146 transaction.rollback() |
|
147 transaction.leave_transaction_management() |
|
148 return |
|
149 |
|
150 # If we found even one object in a fixture, we need to reset the |
|
151 # database sequences. |
124 if object_count > 0: |
152 if object_count > 0: |
125 sequence_sql = connection.ops.sequence_reset_sql(self.style, models) |
153 sequence_sql = connection.ops.sequence_reset_sql(self.style, models) |
126 if sequence_sql: |
154 if sequence_sql: |
127 if verbosity > 1: |
155 if verbosity > 1: |
128 print "Resetting sequences" |
156 print "Resetting sequences" |
129 for line in sequence_sql: |
157 for line in sequence_sql: |
130 cursor.execute(line) |
158 cursor.execute(line) |
131 |
159 |
132 transaction.commit() |
160 if commit: |
133 transaction.leave_transaction_management() |
161 transaction.commit() |
|
162 transaction.leave_transaction_management() |
134 |
163 |
135 if object_count == 0: |
164 if object_count == 0: |
136 if verbosity >= 2: |
165 if verbosity > 1: |
137 print "No fixtures found." |
166 print "No fixtures found." |
138 else: |
167 else: |
139 if verbosity > 0: |
168 if verbosity > 0: |
140 print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count) |
169 print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count) |
|
170 |
|
171 # Close the DB connection. This is required as a workaround for an |
|
172 # edge case in MySQL: if the same connection is used to |
|
173 # create tables, load data, and query, the query can return |
|
174 # incorrect results. See Django #7572, MySQL #37735. |
|
175 if commit: |
|
176 connection.close() |