Задать вопрос

Тел: +7 965 3737 888

558

Просмотров

4

Ответов

Convert an instance to a dictionary for use in newforms

<p>Useful for when you want to use an instance's values as the initial values of a form which you didn't use form_for_instance to create.</p>
<p>Handles foreign keys and many-to-many fields just fine.</p>

Вопрос полезен? Да0/Нет0
file_4892.py(761.0б)
None

Ответы (4):

Ответvandorjw:13.10.2014
Ответ полезен? Да0/Нет0

Previous versions did not properly handle inherited models, or ImageFields

# method to convert a model to a flat dictionary
def instance_to_dict(instance, fields=None, exclude=None):
    """
    Returns a dict containing the data in ``instance`` suitable for 
    converting to JSON.

    ``fields`` is an optional list of field names. If provided, only the named
    fields will be included in the returned dict.

    ``exclude`` is an optional list of field names. If provided, the named
    fields will be excluded from the returned dict, even if they are listed in
    the ``fields`` argument.
    """
    # avoid a circular imports
    from django.db.models.fields import DateField, TimeField
    from django.db.models.fields.files import ImageField
    from django.db.models.fields.related import ForeignKey, OneToOneField

    data = {}

    for field in instance._meta.fields:
        if fields and field.name not in fields:
            continue
        if exclude and field.name in exclude:
            continue
        attr = field.name
        if hasattr(instance, attr): 
            value = getattr(instance, attr)
            if value is not None:
                if isinstance(field, OneToOneField):
                    # knock out duplicate inherited data.
                    # must come before Foreignkey check!
                    continue
                elif isinstance(field, ForeignKey):
                    fkey_values = instance_to_dict(value)
                    for k, v in fkey_values.items():
                        data['%s.%s' % (attr, k)] = v
                    continue
                elif isinstance(field, DateField):
                    value = value.strftime('%Y-%m-%d')
                elif isinstance(field, TimeField):
                    value = value.strftime('%H-%M-%S')
                elif isinstance(field, ImageField):
                    value = value.url
        data[field.name] = value
    for field in instance._meta.many_to_many:
        data[field.name] = [obj._get_pk_val() for obj in getattr(instance, field.attname).all()]
    return data

Ответstuaxo:24.10.2012
Ответ полезен? Да0/Нет0

This turned out to be incompatible with django-filer so I've added a hasattr test.

Now tested + working on django 1.4.1

def instance_dict(instance, key_format=None):
    """
    Returns a dictionary containing field names and values for the given
    instance
    """
    from django.db.models.fields import DateField
    from django.db.models.fields.related import ForeignKey
    if key_format:
        assert '%s' in key_format, 'key_format must contain a %s'
    key = lambda key: key_format and key_format % key or key

    d = {}

    for field in instance._meta.fields:
        attr = field.name
        if hasattr(instance, attr):  # django filer broke without this check
            value = getattr(instance, attr)
            if value is not None:
                if isinstance(field, ForeignKey):
                    fkey_values = instance_dict(value)
                    for k, v in fkey_values.items():
                        d['%s.%s' % (key(attr), k)] = v
                        continue
                elif isinstance(field, DateField):
                    value = value.strftime('%Y-%m-%d')
        d[key(attr)] = value
    for field in instance._meta.many_to_many:
        if pk:
            d[key(field.name)] = [
            obj._get_pk_val()
            for obj in getattr(instance, field.attname).all()]
        else:
            d[key(field.name)] = []
    return d

Ответstuaxo:27.07.2012
Ответ полезен? Да0/Нет0

I've wanted one that could traverse foreign keys.

This adds on the date improvement version above and is tested on django 1.4.

Foreign keys come back as foreignkeyname.foreignkeyvalue in the dictionary, it's recursive so will pull back all the relations (only tested with one level of foreignkey).

def instance_dict(instance, key_format=None):
    """
    Returns a dictionary containing field names and values for the given
    instance
    """
    from django.db.models.fields import DateField
    from django.db.models.fields.related import ForeignKey
    if key_format:
        assert '%s' in key_format, 'key_format must contain a %s'
    key = lambda key: key_format and key_format % key or key

    d = {}
    for field in instance._meta.fields:
        attr = field.name
        value = getattr(instance, attr)
        if value is not None:
            if isinstance(field, ForeignKey):
                fkey_values = instance_dict(value)
                for k, v in fkey_values.items():
                    d['%s.%s' % (key(attr), k)] = v
                    continue
            elif isinstance(field, DateField):
                value = value.strftime('%Y-%m-%d')
        d[key(attr)] = value
    for field in instance._meta.many_to_many:
        if pk:
            d[key(field.name)] = [
            obj._get_pk_val()
            for obj in getattr(instance, field.attname).all()]
        else:
            d[key(field.name)] = []
    return d

Ответakaihola:25.09.2007
Ответ полезен? Да0/Нет0

The function didn't handle dates correctly, at least when feeding instance data to a form with a SelectDateWidget.

I also wanted to use it for unsaved objects, but they failed on many-to-many fields.

Here's a version which fixes both these problems:

def instance_dict(instance, key_format=None):
    """
    Returns a dictionary containing field names and values for the given
    instance
    """
    from django.db.models.fields import DateField
    from django.db.models.fields.related import ForeignKey
    if key_format:
        assert '%s' in key_format, 'key_format must contain a %s'
    key = lambda key: key_format and key_format % key or key

    pk = instance._get_pk_val()
    d = {}
    for field in instance._meta.fields:
        attr = field.name
        value = getattr(instance, attr)
        if value is not None:
            if isinstance(field, ForeignKey):
                value = value._get_pk_val()
            elif isinstance(field, DateField):
                value = value.strftime('%Y-%m-%d')
        d[key(attr)] = value
    for field in instance._meta.many_to_many:
        if pk:
            d[key(field.name)] = [
                obj._get_pk_val()
                for obj in getattr(instance, field.attname).all()]
        else:
            d[key(field.name)] = []
    return d