#3615: Can't define forward references in fixtures using MySQL with InnoDB
-------------------------------------+-------------------------------------
               Reporter:  russellm   |          Owner:  nobody
                   Type:  Bug        |         Status:  new
              Milestone:             |      Component:  Database layer
                Version:  SVN        |  (models, ORM)
             Resolution:             |       Severity:  Normal
           Triage Stage:  Accepted   |       Keywords:  mysql innodb myisam
    Needs documentation:  0          |  reference fixture
Patch needs improvement:  0          |      Has patch:  1
                  UI/UX:  0          |    Needs tests:  0
                                     |  Easy pickings:  0
-------------------------------------+-------------------------------------
Changes (by jsdalton):

 * needs_better_patch:  1 => 0


Comment:

 Okay, an improved patch is now attached. I'm unchecking the patch needs
 improvement flag; if anyone has any issues or concerns please feel free to
 point them out and re-check the flag and I will take a look.

 As mentioned in my previous comment, this patch allows for loading of data
 with forward references in MySQL by turning foreign key checks off
 temporarily. It also offers a mechanism to check the data after it was
 entered to ensure invalid foreign keys were not entered while checks were
 disabled.

 The improved patch just cleans up a few rough edges from the previous
 version.

 * Added tests for `DatabaseIntrospection.get_key_columns()`
 * Create meaningful error message when invalid row found. The message
 includes which row, values and columns triggered the missing foreign key
 error, which is useful for debugging bad data in fixture.
 * Raise error on first bad row. As soon as
 `check_for_invalid_foreign_keys()` hits a bad row, it raises an error.
 Reason for this discussed below.
 * Tweaked the API. The API is now more explicit:
 `disable_foreign_key_checks()` and `enable_foreign_key_checks()`. These
 now return boolean values (always True) when implemented. This means you
 can determine if foreign key checks were disabled and then re-enable and
 check for invalid foreign keys only if they were.
 * Added tests disable/enable checks around necessary tests. I ran through
 the test suite and tried to find places where MySQL required this pattern
 for the test to load properly. I found one or two spots that Karen had in
 her original patch and included those.
 * Document new methods. Documentation was added as needed.

 I didn't want to spend any more time gold plating this, but here are
 possible ways this could be improved. I don't think any are really
 necessary or in the scope of this ticket though.

 * Improve fixture error reporting. As mentioned above, I decided to
 trigger foreign key errors when using  `check_for_invalid_foreign_keys()`
 instead of collecting all bad rows and reporting them in the `loaddata`
 error. The reason is that if we are going to make a feature for MySQL like
 this, it should probably be implemented in all backends. It could be
 useful when debugging bad fixture data, but I think it's unnecessary.
 * Scope foreign key checks to given IDs. Right now,
 `check_for_invalid_foreign_keys()` looks at the entire table and raises an
 `IntegrityError` if it finds any bad data. `loaddata` would then roll back
 the fixture load. An issue could arise where bad data is already
 preexisting in the table where data is being loaded, and thus new data
 would not be loaded because of the `IntegrityError` this would raise, even
 though the new fixture data loaded does not actually have any problems.
 Conceivably, you could pass a list of IDs along with the table name and
 limit the checks to only those, but I felt this was an edge case and not
 worth the complexity.
 * Implement as context manager. It'd be cool to do...

 {{{
 with connection.foreign_key_checks_disabled():
     # Load some data with forward references
 }}}

 ...and then implement the checks in the `__exit__` method of the context
 manager, but I couldn't think of a clean way to pass any of the tables
 touched during any load data activities back to that method for checks.
 Since this is really only used in loaddata and not much anywhere else it's
 also probably overkill IMO.

 I've tested this on MySQL 5.1.4 with InnoDB tables and it looks good. As I
 said, if anyone spots any issues let me know.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/3615#comment:26>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to