# Path: dynamic_rest/meta.py
# def get_model_field_and_type(model, field_name):
#     field = get_model_field(model, field_name)
# 
#     # Django 1.7 (and 1.8?)
#     if isinstance(field, RelatedObject):
#         if isinstance(field.field, OneToOneField):
#             return field, 'o2or'
#         elif isinstance(field.field, ManyToManyField):
#             return field, 'm2m'
#         elif isinstance(field.field, ForeignKey):
#             return field, 'm2o'
#         else:
#             raise RuntimeError("Unexpected field type")
# 
#     # Django 1.9
#     type_map = [
#         (OneToOneField, 'o2o'),
#         (OneToOneRel, 'o2or'),  # is subclass of m2o so check first
#         (ManyToManyField, 'm2m'),
#         (ManyToOneRel, 'm2o'),
#         (ManyToManyRel, 'm2m'),
#         (ForeignKey, 'fk'),  # check last
#     ]
#     for cls, type_str in type_map:
#         if isinstance(field, cls):
#             return field, type_str,
# 
#     return field, '',
# 
# def get_remote_model(field):
#     try:
#         # Django 1.9
#         return field.remote_field.model
#     except BaseException:
#         # Django 1.7
#         if hasattr(field, 'field'):
#             return field.field.model
#         elif hasattr(field, 'rel'):
#             return field.rel.to
#         elif field.__class__.__name__ == 'GenericForeignKey':
#             return None
#         else:
#             raise
# 
# def reverse_m2m_field_name(m2m_field):
#     try:
#         # Django 1.9
#         return m2m_field.remote_field.name
#     except BaseException:
#         # Django 1.7
#         if hasattr(m2m_field, 'rel'):
#             return m2m_field.rel.related_name
#         elif hasattr(m2m_field, 'field'):
#             return m2m_field.field.name
#         elif m2m_field.__class__.__name__ == 'GenericForeignKey':
#             return None
#         else:
#             raise
# 
# def reverse_o2o_field_name(o2or_field):
#     try:
#         # Django 1.9
#         return o2or_field.remote_field.attname
#     except BaseException:
#         # Django 1.7
#         return o2or_field.field.attname


from collections import defaultdict
from django.db import models
from django.db.models import Prefetch, QuerySet
from dynamic_rest.meta import (
    get_model_field_and_type,
    get_remote_model,
    reverse_m2m_field_name,
    reverse_o2o_field_name
)
import copy
import traceback
        return self


class FastPrefetch(object):
    def __init__(self, field, queryset=None):
        if isinstance(queryset, models.Manager):
            queryset = queryset.all()
        if isinstance(queryset, QuerySet):
            queryset = FastQuery(queryset)

        assert (queryset is None or isinstance(queryset, FastQuery))

        self.field = field
        self.query = queryset

    @classmethod
    def make_from_field(cls, model=None, field_name=None, field=None):
        assert (model and field_name) or field, (
            'make_from_field required model+field_name or field'
        )

        # For nested prefetch, only handle first level.
        field_parts = field_name.split('__')
        field_name = field_parts[0]
        nested_prefetches = '__'.join(field_parts[1:])

        field, ftype = get_model_field_and_type(model, field_name)
        if not ftype:
            raise RuntimeError("%s is not prefetchable" % field_name)


# Path: dynamic_rest/meta.py
# def get_model_field_and_type(model, field_name):
#     field = get_model_field(model, field_name)
# 
#     # Django 1.7 (and 1.8?)
#     if isinstance(field, RelatedObject):
#         if isinstance(field.field, OneToOneField):
#             return field, 'o2or'
#         elif isinstance(field.field, ManyToManyField):
#             return field, 'm2m'
#         elif isinstance(field.field, ForeignKey):
#             return field, 'm2o'
#         else:
#             raise RuntimeError("Unexpected field type")
# 
#     # Django 1.9
#     type_map = [
#         (OneToOneField, 'o2o'),
#         (OneToOneRel, 'o2or'),  # is subclass of m2o so check first
#         (ManyToManyField, 'm2m'),
#         (ManyToOneRel, 'm2o'),
#         (ManyToManyRel, 'm2m'),
#         (ForeignKey, 'fk'),  # check last
#     ]
#     for cls, type_str in type_map:
#         if isinstance(field, cls):
#             return field, type_str,
# 
#     return field, '',
# 
# def get_remote_model(field):
#     try:
#         # Django 1.9
#         return field.remote_field.model
#     except BaseException:
#         # Django 1.7
#         if hasattr(field, 'field'):
#             return field.field.model
#         elif hasattr(field, 'rel'):
#             return field.rel.to
#         elif field.__class__.__name__ == 'GenericForeignKey':
#             return None
#         else:
#             raise
# 
# def reverse_m2m_field_name(m2m_field):
#     try:
#         # Django 1.9
#         return m2m_field.remote_field.name
#     except BaseException:
#         # Django 1.7
#         if hasattr(m2m_field, 'rel'):
#             return m2m_field.rel.related_name
#         elif hasattr(m2m_field, 'field'):
#             return m2m_field.field.name
#         elif m2m_field.__class__.__name__ == 'GenericForeignKey':
#             return None
#         else:
#             raise
# 
# def reverse_o2o_field_name(o2or_field):
#     try:
#         # Django 1.9
#         return o2or_field.remote_field.attname
#     except BaseException:
#         # Django 1.7
#         return o2or_field.field.attname


# Path: dynamic_rest/prefetch.py
from collections import defaultdict
from django.db import models
from django.db.models import Prefetch, QuerySet
from dynamic_rest.meta import (
    get_model_field_and_type,
    get_remote_model,
    reverse_m2m_field_name,
    reverse_o2o_field_name
)
import copy
import traceback

        return self


class FastPrefetch(object):
    def __init__(self, field, queryset=None):
        if isinstance(queryset, models.Manager):
            queryset = queryset.all()
        if isinstance(queryset, QuerySet):
            queryset = FastQuery(queryset)

        assert (queryset is None or isinstance(queryset, FastQuery))

        self.field = field
        self.query = queryset

    @classmethod
    def make_from_field(cls, model=None, field_name=None, field=None):
        assert (model and field_name) or field, (
            'make_from_field required model+field_name or field'
        )

        # For nested prefetch, only handle first level.
        field_parts = field_name.split('__')
        field_name = field_parts[0]
        nested_prefetches = '__'.join(field_parts[1:])

        field, ftype = get_model_field_and_type(model, field_name)
        if not ftype:
            raise RuntimeError("%s is not prefetchable" % field_name)


        qs = get_remote_model(field).objects.all()