Wednesday, October 31, 2012

Re: Django/South/MySQL bug

PEBKAC. The query has unescaped '%' symbols in it, which causes the
query to fail. This is not reported, and instead it dies trying to log
the query in connection.queries. I'm sorry to waste your time, should
have single-stepped it before emailing in.

I was clearly using a different query to test at the command line last night.

One curious thing is that the exception seems to be swallowed in
South, but reported from the command line.

Cheers

Tom

On Wed, Oct 31, 2012 at 2:25 PM, Andrew Godwin <andrew@aeracode.org> wrote:
> Hmm, I'm not sure why issuing a query previously isn't fixing it - South
> just uses the same database cursors that the rest of Django uses, it's one
> of the few things we don't mess around with.
>
> Surely Django has to have some code to deal with the case when there isn't
> that attribute already? Have you tried working out why that's not happening?
>
> Andrew
>
> On Wed, Oct 31, 2012 at 2:19 PM, Tom Evans <tevans.uk@googlemail.com> wrote:
>>
>> Hi all
>>
>> I've just run into a slight problem with Django 1.4.1, south 0.7.6 and
>> py-MySQLdb 1.2.3.
>>
>> In the fix for Django bug #14091, Django will now always look at
>> cursor._last_executed in order to get details of the last query
>> executed, which I guess is for managing connection.queries in debug
>> mode. However, it does not check for existence of this attribute,
>> which will only exist if you have already executed a query from my
>> reading of py-MySQLdb.
>>
>> cursor._last_executed is an undocumented 'private' part of py-MySQLdb.
>>
>> For some reason, trying to issue a raw DB query in a south migration
>> causes Django to die looking at that attribute. Either using south's
>> "db.execute", or using "from django.db import connection;
>> c=connection.cursor(); c.execute(..)" as described in the Django
>> manual results in the same back trace.
>>
>> This issue only came about because I needed to do a south data
>> migration that could not efficiently be handled in the ORM. Using the
>> ORM - either Django's or South's - in the migration works fine. I also
>> tried issueing a query through the ORM first to attempt to cause the
>> attribute to be set, but this also fails.
>>
>> The migration is straightforward, it is adding a hash algorithm so
>> that we can move back closer to Django's stock auth stack:
>>
>> def forwards(self, orm):
>> from django.db import connection
>> c = connection.cursor()
>> c.execute(
>> """
>> UPDATE auth_user SET password = 'customsha512$' + password
>> WHERE password != '!' AND password != '' AND password not like
>> '%$%'
>> """)
>>
>> The traceback looks like this:
>>
>> Traceback (most recent call last):
>> File "manage.py", line 9, in <module>
>> execute_from_command_line(sys.argv)
>> File "lib/django/core/management/__init__.py", line 443, in
>> execute_from_command_line
>> utility.execute()
>> File "lib/django/core/management/__init__.py", line 382, in execute
>> self.fetch_command(subcommand).run_from_argv(self.argv)
>> File "lib/django/core/management/base.py", line 196, in run_from_argv
>> self.execute(*args, **options.__dict__)
>> File "lib/django/core/management/base.py", line 232, in execute
>> output = self.handle(*args, **options)
>> File "lib/south/management/commands/migrate.py", line 108, in handle
>> ignore_ghosts = ignore_ghosts,
>> File "lib/south/migration/__init__.py", line 213, in migrate_app
>> success = migrator.migrate_many(target, workplan, database)
>> File "lib/south/migration/migrators.py", line 235, in migrate_many
>> result = migrator.__class__.migrate_many(migrator, target,
>> migrations, database)
>> File "lib/south/migration/migrators.py", line 310, in migrate_many
>> result = self.migrate(migration, database)
>> File "lib/south/migration/migrators.py", line 133, in migrate
>> result = self.run(migration)
>> File "lib/south/migration/migrators.py", line 107, in run
>> return self.run_migration(migration)
>> File "lib/south/migration/migrators.py", line 81, in run_migration
>> migration_function()
>> File "lib/south/migration/migrators.py", line 57, in <lambda>
>> return (lambda: direction(orm))
>> File "project/idp/migrations/0049_add_mintel_pw_algo.py", line 17, in
>> forwards
>> """)
>> File "lib/south/db/generic.py", line 273, in execute
>> cursor.execute(sql, params)
>> File "lib/django/db/backends/util.py", line 44, in execute
>> sql = self.db.ops.last_executed_query(self.cursor, sql, params)
>> File "lib/django/db/backends/mysql/base.py", line 237, in
>> last_executed_query
>> return cursor._last_executed
>> File "lib/django/db/backends/mysql/base.py", line 144, in __getattr__
>> return getattr(self.cursor, attr)
>> AttributeError: 'Cursor' object has no attribute '_last_executed'
>>
>> If I attempt to do the same operation from the shell, it works
>> correctly. Therefore, I think there must be something specific to
>> South that is happening. Any tips or hints would be greatly
>> appreciated!
>>
>> Cheers
>>
>> Tom
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "South Users" group.
>> To post to this group, send email to south-users@googlegroups.com.
>> To unsubscribe from this group, send email to
>> south-users+unsubscribe@googlegroups.com.
>> For more options, visit this group at
>> http://groups.google.com/group/south-users?hl=en.
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "South Users" group.
> To post to this group, send email to south-users@googlegroups.com.
> To unsubscribe from this group, send email to
> south-users+unsubscribe@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/south-users?hl=en.

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

No comments:

Post a Comment