ipp/relevamiento/perms.py
class RequiereCoordJurisdiccional(RequiereRol):
    permiso_minimo = PERMISO_COORD_JURISDICCIONAL
ipp/relevamiento/models.py
class Comercio(models.Model):
    nombre = models.CharField(max_length=100)
    direccion = models.CharField("dirección", max_length=100)
    tipo = models.CharField("tipo de comercio", max_length=100)
    descripcion = models.CharField("descripción", max_length=256, blank=True)
    zona =  models.ForeignKey(Zona, related_name="comercios")

    def __str__(self):
        return self.nombre
ipp/relevamiento/constants.py
PERMISO_COORD_GRAL = 5
ipp/relevamiento/models.py
class Jurisdiccion(models.Model):
    region = models.ForeignKey(Region, related_name="jurisdicciones")
    nombre = models.CharField(max_length=100)

    def __str__(self):
        return str(self.region) +" > "+ self.nombre

    class Meta:
        verbose_name = "jurisdicción"
        verbose_name_plural = "jurisdicciones"
        ordering = ['region__pk', 'nombre']
        unique_together = (("region", "nombre"))
ipp/relevamiento/perms.py
class RequiereCoordZonal(RequiereRol):
    permiso_minimo = PERMISO_COORD_ZONAL
ipp/relevamiento/models.py
class Zona(models.Model):
    jurisdiccion = models.ForeignKey(Jurisdiccion, related_name="zonas")
    nombre = models.CharField(max_length=100)

    def __str__(self):
        return str(self.jurisdiccion) +" > "+ self.nombre

    class Meta:
        ordering = ['jurisdiccion__region__pk', 'jurisdiccion__nombre', 'nombre']
        unique_together = (("jurisdiccion", "nombre"))
ipp/relevamiento/models.py
class JerarquizacionMarca(models.Model):
    MARCA_CHOICES = (
        ("premium", "premium"),
        ("media", "media"),
        ("economica", "económica")
    )
    planilla_de_relevamiento = models.ForeignKey("PlanillaDeRelevamiento")
    producto_con_marca = models.ForeignKey(ProductoConMarca, related_name="jerarquizaciones", verbose_name="producto")
    tipo_marca = models.CharField(choices=MARCA_CHOICES, max_length=15)
    def __str__(self):
        return "%s (marca %s)" %\
            (str(self.producto_con_marca), self.tipo_marca)

    class Meta:
        unique_together = (("planilla_de_relevamiento", "producto_con_marca"),)
ipp/relevamiento/constants.py
COORD_REGIONAL = "coordinador_regional"
ipp/relevamiento/constants.py
COORD_GRAL = "coordinador_general"
ipp/relevamiento/constants.py
COORD_JURISDICCIONAL = "coordinador_jurisdiccional"
ipp/relevamiento/models.py
class Lectura(models.Model):
    producto_con_marca = models.ForeignKey(ProductoConMarca, verbose_name="producto")
    precio = models.FloatField()
    fecha = models.DateField(default=datetime.now)
    muestra = models.ForeignKey('Muestra', related_name="lecturas")
#    relevador = models.ForeignKey(Perfil)

    def __str__(self):
        return "%s $%s (%s)" % \
            (str(self.producto_con_marca), str(self.precio), str(self.fecha))

    class Meta:
        unique_together = (("producto_con_marca", "muestra"),)
ipp/relevamiento/constants.py
COORD_ZONAL = "coordinador_zonal"
ipp/relevamiento/models.py
class Perfil(models.Model):
    ROLES_CHOICES = (
        (RELEVADOR, RELEVADOR),
        (COORD_ZONAL, COORD_ZONAL),
        (COORD_JURISDICCIONAL, COORD_JURISDICCIONAL),
        (COORD_REGIONAL, COORD_REGIONAL),
        (COORD_GRAL, COORD_GRAL)
    )
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    rol = models.CharField(choices=ROLES_CHOICES, default=RELEVADOR, max_length=40)
    telefono = models.CharField("teléfono", max_length=100, blank=True)
    celular = models.CharField(max_length=100, blank=True)
    enlace = models.URLField(blank=True)
    notas = models.TextField(blank=True)
    regiones = models.ManyToManyField(Region, blank=True)
    jurisdicciones = models.ManyToManyField(Jurisdiccion, blank=True)
    zonas = models.ManyToManyField(Zona, blank=True, related_name="perfiles")

    def __str__(self):
        return self.user.username

    @property
    def autorizacion(self):
        if self.rol == RELEVADOR: return PERMISO_RELEVADOR
        elif self.rol == COORD_ZONAL: return PERMISO_COORD_ZONAL
        elif self.rol == COORD_JURISDICCIONAL: return PERMISO_COORD_JURISDICCIONAL
        elif self.rol == COORD_REGIONAL: return PERMISO_COORD_REGIONAL
        elif self.rol == COORD_GRAL: return PERMISO_COORD_GRAL
        else: return 0

    @property
    def regiones_permitidas(self):
        if self.rol == COORD_REGIONAL:
            return self.regiones
        elif self.rol == COORD_GRAL:
            return Region.objects.all()
        else:
            return Region.objects.none()

    @property
    def jurisdicciones_permitidas(self):
        if self.rol == COORD_JURISDICCIONAL:
            return self.jurisdicciones
        elif self.rol == COORD_REGIONAL:
            return Jurisdiccion.objects.filter(region__in=self.regiones.all())
        elif self.rol == COORD_GRAL:
            return Jurisdiccion.objects.all()
        else:
            return Jurisdiccion.objects.none()

    @property
    def zonas_permitidas(self):
        if self.rol in [RELEVADOR, COORD_ZONAL]:
            return self.zonas
        elif self.rol == COORD_JURISDICCIONAL:
            return Zona.objects.filter(jurisdiccion__in=self.jurisdicciones.all())
        elif self.rol == COORD_REGIONAL:
            return Zona.objects.filter(jurisdiccion__region__in=self.regiones.all())
        elif self.rol == COORD_GRAL:
            return Zona.objects.all()
        else:
            return Zona.objects.none()
        
    class Meta:
        verbose_name_plural = "perfiles"
ipp/relevamiento/constants.py
PERMISO_COORD_ZONAL = 2
ipp/relevamiento/models.py
class Region(models.Model):
    nombre = models.CharField(max_length=100, unique=True)

    def __str__(self):
        return self.nombre

    class Meta:
        verbose_name = "región"
        verbose_name_plural = "regiones"
ipp/relevamiento/forms.py
class JerarquizacionMarcaForm(autocomplete_light.ModelForm):
    class Meta:
class ProductoConMarcaForm(ModelForm):
    class Meta:
class PlanillaDeRelevamientoForm(ModelForm):
    class Meta:
class MuestraForm(ModelForm):
    class Meta:
class LecturaForm(ModelForm):
    class Meta:
class UserFormCreacion(UserCreationForm):
    class Meta:
class UserFormEdicion(ModelForm):
    class Meta:
class PerfilInlineFormSet(BaseInlineFormSet):
class VariacionForm(Form):
    def __init__(self, *args, **kwargs):
    def clean_producto_con_marca(self):
    def clean(self):
    def __init__(self, *args, **kwargs):
    def clean(self):
    def __init__(self, *args, **kwargs):
    def clean_planilla_modelo(self):
    def clean_zona(self):
    def clean_comercio(self):
    def clean(self):
    def __init__(self, *args, **kwargs):
    def __init__(self, *args, **kwargs):
    def __init__(self, *args, **kwargs):
    def clean(self):
ipp/relevamiento/models.py
class Comercio(models.Model):
    nombre = models.CharField(max_length=100)
    direccion = models.CharField("dirección", max_length=100)
    tipo = models.CharField("tipo de comercio", max_length=100)
    descripcion = models.CharField("descripción", max_length=256, blank=True)
    zona =  models.ForeignKey(Zona, related_name="comercios")

    def __str__(self):
        return self.nombre
ipp/relevamiento/models.py
class PlanillaDeRelevamiento(models.Model):
    """Basada en una Planilla Modelo, establece qué marcas se relevarán para un comercio específico"""
    planilla_modelo = models.ForeignKey(PlanillaModelo)
    zona = models.ForeignKey(Zona, related_name="planillas_de_relevamiento")
    comercio = models.ForeignKey(Comercio, related_name="planillas_de_relevamiento")
    productos = models.ManyToManyField(ProductoConMarca,
                                       through=JerarquizacionMarca, blank=True)
    habilitada = models.BooleanField(default=False)

    def __str__(self):
        return "%s (%s)" % \
            (str(self.comercio), str(self.zona))

    class Meta:
        unique_together = (("planilla_modelo", "zona", "comercio"),)
        verbose_name_plural = "planillas de relevamiento"
        ordering = ['planilla_modelo__nombre', 'zona']
ipp/relevamiento/constants.py
PERMISO_COORD_REGIONAL = 4
ipp/relevamiento/models.py
class ProductoConMarca(models.Model):
    producto_generico = models.ForeignKey(ProductoGenerico)
    marca = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return "%s %s" %\
            (str(self.producto_generico), self.marca)

    class Meta:
        verbose_name="producto"
        verbose_name_plural="productos"
        unique_together = (("producto_generico", "marca"),)
ipp/relevamiento/models.py
class Muestra(models.Model):
    """Muestra de lecturas quincenales para un comercio"""
    planilla_de_relevamiento = models.ForeignKey(PlanillaDeRelevamiento, related_name="muestras")
    anio = models.IntegerField("año")
    mes = models.IntegerField(choices=MES_CHOICES)
    quincena = models.IntegerField(choices=((1, "primera"),(2, "segunda")))
    relevadores = models.ManyToManyField(Perfil, blank=True)
    completa = models.BooleanField(default=False)
    aprobada = models.BooleanField(default=False)
    
    def __str__(self):
        nombre = "%s (%s/%s, quincena %s)" %\
                 (str(self.planilla_de_relevamiento), self.mes, self.anio, self.quincena)
        return nombre

    class Meta:
        unique_together = (("planilla_de_relevamiento", "anio", "mes", "quincena"),)
        ordering = ['-anio', '-mes', '-quincena']
ipp/relevamiento/constants.py
PERMISO_RELEVADOR = 1
ipp/relevamiento/models.py
class JerarquizacionMarca(models.Model):
    MARCA_CHOICES = (
        ("premium", "premium"),
        ("media", "media"),
        ("economica", "económica")
    )
    planilla_de_relevamiento = models.ForeignKey("PlanillaDeRelevamiento")
    producto_con_marca = models.ForeignKey(ProductoConMarca, related_name="jerarquizaciones", verbose_name="producto")
    tipo_marca = models.CharField(choices=MARCA_CHOICES, max_length=15)
    def __str__(self):
        return "%s (marca %s)" %\
            (str(self.producto_con_marca), self.tipo_marca)

    class Meta:
        unique_together = (("planilla_de_relevamiento", "producto_con_marca"),)
ipp/relevamiento/models.py
class PlanillaDeRelevamiento(models.Model):
    """Basada en una Planilla Modelo, establece qué marcas se relevarán para un comercio específico"""
    planilla_modelo = models.ForeignKey(PlanillaModelo)
    zona = models.ForeignKey(Zona, related_name="planillas_de_relevamiento")
    comercio = models.ForeignKey(Comercio, related_name="planillas_de_relevamiento")
    productos = models.ManyToManyField(ProductoConMarca,
                                       through=JerarquizacionMarca, blank=True)
    habilitada = models.BooleanField(default=False)

    def __str__(self):
        return "%s (%s)" % \
            (str(self.comercio), str(self.zona))

    class Meta:
        unique_together = (("planilla_modelo", "zona", "comercio"),)
        verbose_name_plural = "planillas de relevamiento"
        ordering = ['planilla_modelo__nombre', 'zona']
ipp/relevamiento/constants.py
RELEVADOR = "relevador"
ipp/relevamiento/perms.py
class RequiereCoordRegional(RequiereRol):
    permiso_minimo = PERMISO_COORD_REGIONAL
ipp/relevamiento/models.py
class PlanillaModelo(models.Model):
    """Planilla que establece qué productos se relevarán en todo el sistema"""
    nombre = models.CharField(max_length=100)
    productos = models.ManyToManyField(ProductoGenerico,
                                       through=ProductoEnPlanilla, blank=True)
    habilitada = models.BooleanField(default=False)

    def __str__(self):
        return self.nombre

    class Meta:
        verbose_name_plural="planillas modelo"
ipp/relevamiento/constants.py
PERMISO_COORD_JURISDICCIONAL = 3
ipp/relevamiento/models.py
class ProductoGenerico(models.Model):
    rubro = models.ForeignKey(Rubro)
    nombre = models.CharField(max_length=150)
    medida = models.CharField(max_length=20)

    def __str__(self):
        return "%s > %s (%s)" % (self.rubro, self.nombre, self.medida)
    
    class Meta:
        verbose_name_plural="productos genericos"


Question: from collections import OrderedDict
from django.http import Http404
from django.http import HttpResponseRedirect
from django.shortcuts import render, HttpResponse, redirect
from django.forms.models import inlineformset_factory
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.list import ListView
from django.contrib.auth.models import User
from django.db.models import Q, F, Avg, Max, Min, Count
from django.db.models.functions import Concat
from django.utils.text import slugify
from .constants import PERMISO_RELEVADOR, PERMISO_COORD_ZONAL, PERMISO_COORD_JURISDICCIONAL,\
    PERMISO_COORD_REGIONAL, PERMISO_COORD_GRAL, RELEVADOR, COORD_ZONAL, COORD_JURISDICCIONAL,\
    COORD_REGIONAL, COORD_GRAL
from .forms import PlanillaDeRelevamientoForm, JerarquizacionMarcaForm, ProductoConMarcaForm,\
    MuestraForm, LecturaForm, UserFormCreacion, UserFormEdicion, PerfilFormSet, VariacionForm
from .models import PlanillaModelo, PlanillaDeRelevamiento, JerarquizacionMarca, ProductoGenerico,\
    ProductoConMarca, Lectura, Comercio, Perfil, Muestra, PlanillaDeRelevamiento, JerarquizacionMarca,\
    Zona, Comercio, Jurisdiccion, Region
from .perms import RequiereCoordZonal, RequiereCoordJurisdiccional, RequiereCoordRegional
import unicodecsv as csv
        messages.success(request, 'Lectura para <strong>%s</strong> eliminada.' % lectura.producto_con_marca)
        return redirect(reverse("relevamiento:editar_muestra",
                                kwargs={"muestra_id": muestra_id}))


class SeleccionarComercio(RequiereCoordZonal, ListView):
    model = Comercio
    template_name = "relevamiento/seleccionar_comercio.html"
    def get_queryset(self):
        qs = super(SeleccionarComercio, self).get_queryset()
        return qs.filter(zona__in=self.request.user.perfil.zonas_permitidas.all())

class ComercioBase(RequiereCoordZonal):
    model = Comercio
    success_message = "Comercio guardado con éxito"
    fields = "__all__"

    def get_context_data(self, **kwargs):
        context = super(ComercioBase, self).get_context_data(**kwargs)
        context['form'].fields['zona'].queryset = self.request.user.perfil.zonas_permitidas.all()
        return context

    def form_valid(self, form):
        messages.success(self.request, self.success_message)
        return super(ComercioBase, self).form_valid(form)  

class CrearComercio(ComercioBase, CreateView):
    template_name = "relevamiento/crear_comercio.html"
    success_url = "/"
    success_message = "Comercio creado con éxito."


class EditarComercio(ComercioBase, UpdateView):
    template_name = "relevamiento/crear_comercio.html"
    success_url = "/"
    success_message = "Comercio actualizado con éxito."

class SeleccionarZona(RequiereCoordJurisdiccional, ListView):
    model = Zona
    template_name = "relevamiento/seleccionar_zona.html"

    def get_queryset(self):
        return self.request.user.perfil.zonas_permitidas.all()

class ZonaBase(RequiereCoordJurisdiccional):
    model = Zona
    success_message = "Zona guardada con éxito"
    fields = "__all__"

    def get_context_data(self, **kwargs):
        context = super(ZonaBase, self).get_context_data(**kwargs)
        jurisdicciones_permitidas = self.request.user.perfil.jurisdicciones_permitidas.all()
        context['form'].fields['jurisdiccion'].queryset = jurisdicciones_permitidas
        return context

    def form_valid(self, form):
        messages.success(self.request, self.success_message)
        return super(ZonaBase, self).form_valid(form)  


class CrearZona(ZonaBase, CreateView):
    template_name = "relevamiento/crear_zona.html"
    success_url = "/"
    success_message = "Zona creada con éxito."


class EditarZona(ZonaBase, UpdateView):
    template_name = "relevamiento/crear_zona.html"
    success_url = "/"
    success_message = "Zona actualizada con éxito."


class SeleccionarJurisdiccion(RequiereCoordRegional, ListView):
    model = Jurisdiccion
    template_name = "relevamiento/seleccionar_jurisdiccion.html"

    def get_queryset(self):
#        qs = super(SeleccionarJurisdiccion, self).get_queryset()
        qs = self.request.user.perfil.jurisdicciones_permitidas.all()
        return qs

class JurisdiccionBase(RequiereCoordRegional):
    model = Jurisdiccion
    success_message = "Jurisdicción guardada con éxito"
    fields = "__all__"

    def get_context_data(self, **kwargs):
        context = super(JurisdiccionBase, self).get_context_data(**kwargs)
        context['form'].fields['region'].queryset = Region.objects.filter(
            pk__in=self.request.user.perfil.regiones_permitidas.all())
        return context

    def form_valid(self, form):
        messages.success(self.request, self.success_message)
        return super(JurisdiccionBase, self).form_valid(form)  

class CrearJurisdiccion(JurisdiccionBase, CreateView):
    template_name = "relevamiento/crear_jurisdiccion.html"
    success_url = "/"
    success_message = "Jurisdiccion creada con éxito."


class EditarJurisdiccion(JurisdiccionBase, UpdateView):
    template_name = "relevamiento/crear_jurisdiccion.html"
    success_url = "/"
    success_message = "Jurisdiccion actualizada con éxito."


class UserBase(RequiereCoordZonal):
    template_name = 'relevamiento/crear_user.html'
    model = User

    def get(self, request, *args, **kwargs):
        if not self.kwargs.get("pk", None):
            self.object = None
        else:
            self.object = self.get_object()
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        if self.object:

Answer:             perfil_form = PerfilFormSet(instance=self.object)