from copy import deepcopy
from django.conf import settings
from django.contrib.auth.models import User
from django.core import mail
from django.http import (JsonResponse, HttpResponseNotAllowed,
                         HttpResponseRedirect)
from django.shortcuts import get_object_or_404, resolve_url
from django.template.loader import render_to_string
from django.views.decorators.csrf import csrf_exempt
from InternetSemLimites.core.forms import ProviderForm
from InternetSemLimites.core.models import Provider, State


def home(request):
    fame = _serialize_query(Provider.objects.fame())
    shame = _serialize_query(Provider.objects.shame())
    return _to_json(fame, shame)


def fame(request):
    providers = _serialize_query(Provider.objects.fame())
    return _to_json(providers)


def shame(request):
    providers = _serialize_query(Provider.objects.shame())
    return _to_json(providers)


def by_state(request, abbr):
    state = get_object_or_404(State, abbr=abbr.upper())
    fame = _serialize_query(state.provider_set.fame())
    shame = _serialize_query(state.provider_set.shame())
    return _to_json(fame, shame)


def fame_by_state(request, abbr):
    providers = _serialize_query(_providers_by_state(abbr).fame())
    return _to_json(providers)


def shame_by_state(request, abbr):
    providers = _serialize_query(_providers_by_state(abbr).shame())
    return _to_json(providers)


def provider_detail(request, pk):
    provider = get_object_or_404(Provider, pk=pk)
    return JsonResponse({'provider': _serialize_object(provider, True)})


@csrf_exempt
def provider(request, pk):
    routes = {
        'GET': provider_detail,
        'POST': provider_edit
    }

    route = routes.get(request.method)

    if route:
        return route(request, pk)
    return HttpResponseNotAllowed([method for method in routes])


@csrf_exempt
def provider_new(request):
    if request.method != 'POST':
        return HttpResponseNotAllowed(['POST'])

    form = ProviderForm(request.POST)
    if not form.is_valid():
        return JsonResponse({'errors': form.errors})

    provider = form.save()
    _send_mail('+1 InternetSemLimites',
               settings.DEFAULT_FROM_EMAIL,
               list(_get_admin_emails()),
               'core/provider_email.txt',
               dict(provider=provider))

    return HttpResponseRedirect(resolve_url('api:provider', provider.pk))


@csrf_exempt
def provider_edit(request, pk):

    provider_original = get_object_or_404(Provider, pk=pk)

    provider_edited = deepcopy(provider_original)
    provider_edited.id = None
    provider_edited.edited_from = provider_original
    provider_edited.status = Provider.EDIT

    provider_edited_form = ProviderForm(request.POST, instance=provider_edited)

    if not provider_edited_form.is_valid():
        return JsonResponse({'errors': provider_edited_form.errors}, status=422)

    provider_edited_form.save()

    _send_mail('+1 InternetSemLimites',
               settings.DEFAULT_FROM_EMAIL,
               list(_get_admin_emails()),
               'core/provider_edit_email.txt',
               dict(
                   provider_original=provider_original,
                   provider_edited=provider_edited,

               ))

    return HttpResponseRedirect(resolve_url('api:provider', provider_edited.pk))


def _providers_by_state(abbr):
    state = get_object_or_404(State, abbr=abbr.upper())
    return state.provider_set


def _to_json(providers_or_fame, shame=None):
    if shame:
        ctx = {'hall-of-fame': list(providers_or_fame),
               'hall-of-shame': list(shame)}
    else:
        ctx = {'providers': list(providers_or_fame)}
    return JsonResponse(ctx)


def _serialize_query(query):
    for obj in query:
        yield _serialize_object(obj)


def _serialize_object(obj, after_post=False):
    fields = [f.__str__().split('.')[-1] for f in Provider._meta.fields]
    fields.remove('id')
    fields.remove('status')
    fields.remove('edited_from')
    output = {field: getattr(obj, field) for field in fields}
    output['coverage'] = obj.coverage_to_list
    output['category'] = obj.category_name
    if after_post:
        output['moderation_reason'] = obj.get_moderation_reason()
        output['status'] = obj.get_status()
    return output


def _get_admin_emails():
    for user in User.objects.exclude(email=''):
        yield user.email


def _send_mail(subject, sender, to, template_name, context):
    body = render_to_string(template_name, context)
    mail.send_mail(subject, body, sender, to)

@@ -3830,24 +3830,28 @@
 False):%0A    
+all_
 fields = %5Bf.
@@ -3847,17 +3847,20 @@
 ields = 
-%5B
+set(
 f.__str_
@@ -3912,93 +3912,112 @@
 elds
-%5D
+)
 %0A    
-fields.remove('id')%0A    fields.remove('status')%0A    fields.remove('edited_from'
+ignore_fields = set(%5B'id', 'status', 'edited_from'%5D)%0A    fields = tuple(all_fields - ignore_fields
 )%0A  

Remove bunch of .remove methods using set calculation