On 13 avr. 2015, at 20:13, Aymeric Augustin 
<aymeric.augus...@polytechnique.org> wrote:

> Replacing adapters is a bit more tricky. Removing them causes the two
> regression tests for #17755 to fail. I haven't determined how I can process
> parameters passed to QuerySet.raw(), but since that's part of the ORM, I'm
> optimistic.

Well… I was optimistic :-) I need help.

I’m looking for a way to fix https://code.djangoproject.com/ticket/17755
without registering adapters at the level of the DB-API module (sqlite3,
MySQLdb, etc.)

In a regular QuerySet / Query, a parameter is tied to a field (or equivalent,
like an expression, which has an output field). The field's get_db_prep_value
method is used to transform the parameter to an appropriate value for the
DB-API module. In general, datetime objects are handled by a DateTimeField,
whose get_db_prep_value method calls connection.ops.value_to_db_datetime, and
everything is fine.

Unfortunately, a RawQuerySet / RawQuery cannot use the same logic because its
parameters aren't tied to fields. For lack of a better idea, I'm proposing to
add a best-effort conversion function to BaseDatabaseOperations:

    def value_to_db(self, value):
        """
        Transforms a value to something compatible with the backend driver.

        This method only depends on the type of the value. It's designed for
        cases where the target type isn't known. As a consequence it may not
        work perfectly in all circumstances.
        """
        if isinstance(value, datetime.datetime):   # must be before date
            return self.value_to_db_datetime(value)
        elif isinstance(value, datetime.date):
            return self.value_to_db_date(value)
        elif isinstance(value, datetime.time):
            return self.value_to_db_time(value)
        elif isinstance(value, decimal.Decimal):
            return self.value_to_db_decimal(value)
        else:
            return value

Then I will invoke this method on all parameters, most likely in
RawQuery._execute_query. This is the last step in the call chain:

    Model.objects.raw
        -> RawQuerySet.__iter__
            -> RawQuery.__iter__
            -> RawQuery._execute_query
                -> cursor.execute

Does that make sense?

I know that I'm duplicating the functionality of database adapters, but I
don't have much choice if I don't want to touch the default global adapters.

-- 
Aymeric.




-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/D6217D53-6933-43AB-93D9-8B735F1C5FA8%40polytechnique.org.
For more options, visit https://groups.google.com/d/optout.

Reply via email to