| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 | """
Helper functions for returning the field information that is associated
with a model class.
"""
from collections import namedtuple
from django.db import models
from django.utils import six
from django.utils.datastructures import SortedDict
import inspect
FieldInfo = namedtuple('FieldResult', ['pk', 'fields', 'forward_relations', 'reverse_relations'])
RelationInfo = namedtuple('RelationInfo', ['field', 'related', 'to_many', 'has_through_model'])
def _resolve_model(obj):
    """
    Resolve supplied `obj` to a Django model class.
    `obj` must be a Django model class itself, or a string
    representation of one.  Useful in situtations like GH #1225 where
    Django may not have resolved a string-based reference to a model in
    another model's foreign key definition.
    String representations should have the format:
        'appname.ModelName'
    """
    if isinstance(obj, six.string_types) and len(obj.split('.')) == 2:
        app_name, model_name = obj.split('.')
        return models.get_model(app_name, model_name)
    elif inspect.isclass(obj) and issubclass(obj, models.Model):
        return obj
    raise ValueError("{0} is not a Django model".format(obj))
def get_field_info(model):
    """
    Given a model class, returns a `FieldInfo` instance containing metadata
    about the various field types on the model.
    """
    opts = model._meta.concrete_model._meta
    # Deal with the primary key.
    pk = opts.pk
    while pk.rel and pk.rel.parent_link:
        # If model is a child via multitable inheritance, use parent's pk.
        pk = pk.rel.to._meta.pk
    # Deal with regular fields.
    fields = SortedDict()
    for field in [field for field in opts.fields if field.serialize and not field.rel]:
        fields[field.name] = field
    # Deal with forward relationships.
    forward_relations = SortedDict()
    for field in [field for field in opts.fields if field.serialize and field.rel]:
        forward_relations[field.name] = RelationInfo(
            field=field,
            related=_resolve_model(field.rel.to),
            to_many=False,
            has_through_model=False
        )
    # Deal with forward many-to-many relationships.
    for field in [field for field in opts.many_to_many if field.serialize]:
        forward_relations[field.name] = RelationInfo(
            field=field,
            related=_resolve_model(field.rel.to),
            to_many=True,
            has_through_model=(
                not field.rel.through._meta.auto_created
            )
        )
    # Deal with reverse relationships.
    reverse_relations = SortedDict()
    for relation in opts.get_all_related_objects():
        accessor_name = relation.get_accessor_name()
        reverse_relations[accessor_name] = RelationInfo(
            field=None,
            related=relation.model,
            to_many=relation.field.rel.multiple,
            has_through_model=False
        )
    # Deal with reverse many-to-many relationships.
    for relation in opts.get_all_related_many_to_many_objects():
        accessor_name = relation.get_accessor_name()
        reverse_relations[accessor_name] = RelationInfo(
            field=None,
            related=relation.model,
            to_many=True,
            has_through_model=(
                hasattr(relation.field.rel, 'through') and
                not relation.field.rel.through._meta.auto_created
            )
        )
    return FieldInfo(pk, fields, forward_relations, reverse_relations)
 |