netzkolchose / django-fast-update

Faster db updates using UPDATE FROM VALUES sql variants.
MIT License
21 stars 2 forks source link

ForeignKeys with null=True aren't handled correctly in copy_update #3

Closed mikicz closed 2 years ago

mikicz commented 2 years ago

If a field is a ForeignKey and it's used in copy_update and a None value is provided in one of the objects that's being update, the copy_update fails with

TypeError: expected type <class 'int'>

I've drilled down to why and the cause is in get_encoder, for foreign keys it gets the encoder for the primary key of the related object, which will never be null=True.

When I patched it to the following, all my tests started passing.

def get_encoder(field, null=None):
    """Get registered encoder for field."""
    if field.is_relation:
        return get_encoder(field.target_field, null=field.null)
    if isinstance(field, ArrayField):
        return array_factory(field)
    for cls in type(field).__mro__:
        enc = ENCODERS.get(cls)
        if enc:
            return enc[null or field.null]
    raise NotImplementedError(f'no suitable encoder found for field {field}')
jerch commented 2 years ago

Wow nice catch, thats indeed pulling the null-state from the wrong field.