# coding: utf-8

from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.db.models.fields.related_descriptors import (
    ForwardManyToOneDescriptor as BaseForwardManyToOneDescriptor,
    ForwardOneToOneDescriptor as BaseForwardOneToOneDescriptor,
    ReverseOneToOneDescriptor as BaseReverseOneToOneDescriptor,
)


class RelatedDescriptorMixin(object):
    def __get__(self, instance, cls=None):

        if instance is None:
            return self

        try:
            return getattr(instance, self.cache_name)
        except AttributeError:
            raise ImproperlyConfigured(
                "Field `%s' is not cached" % self.related.name
            )


class ForwardManyToOneDescriptor(
    RelatedDescriptorMixin, BaseForwardManyToOneDescriptor
):
    pass


class ForwardOneToOneDescriptor(BaseForwardOneToOneDescriptor):
    pass


class ReverseOneToOneDescriptor(
    RelatedDescriptorMixin, BaseReverseOneToOneDescriptor
):
    pass


class ForeignKey(models.ForeignKey):
    forward_related_accessor_class = ForwardManyToOneDescriptor


class OneToOneField(models.OneToOneField):
    forward_related_accessor_class = ForwardOneToOneDescriptor
    related_accessor_class = ReverseOneToOneDescriptor


class Model(models.Model):
    def refresh_from_db(self, using=None, fields=None):
        for field in fields:
            if field in self.get_deferred_fields():
                raise ImproperlyConfigured("`%s' is deferred" % field)
        return super().refresh_from_db(using=using, fields=fields)

    class Meta:
        abstract = True
