2010-05-14 9 views
5

que tiene un modelo LoggedEvent base y una serie de modelos de subclase como sigue:Anotar sobre la herencia multi-mesa en Django

class LoggedEvent(models.Model): 
    user = models.ForeignKey(User, blank=True, null=True) 
    timestamp = models.DateTimeField(auto_now_add=True) 

class AuthEvent(LoggedEvent): 
    good = models.BooleanField() 
    username = models.CharField(max_length=12) 

class LDAPSearchEvent(LoggedEvent): 
    type = models.CharField(max_length=12) 
    query = models.CharField(max_length=24) 

class PRISearchEvent(LoggedEvent): 
    type = models.CharField(max_length=12) 
    query = models.CharField(max_length=24) 

Los usuarios generan estos eventos como lo hacen las acciones relacionadas. Estoy intentando generar un informe de uso de cuántos de cada tipo de evento ha causado cada usuario en el último mes. Estoy luchando con el ORM de Django y, mientras estoy cerca, me encuentro con un problema. Aquí está el código de consulta:

def usage(request): 
    # Calculate date range 
    today = datetime.date.today() 
    month_start = datetime.date(year=today.year, month=today.month - 1, day=1) 
    month_end = datetime.date(year=today.year, month=today.month, day=1) - datetime.timedelta(days=1) 

    # Search for how many LDAP events were generated per user, last month 
    baseusage = User.objects.filter(loggedevent__timestamp__gte=month_start, loggedevent__timestamp__lte=month_end) 
    ldapusage = baseusage.exclude(loggedevent__ldapsearchevent__id__lt=1).annotate(count=Count('loggedevent__pk')) 
    authusage = baseusage.exclude(loggedevent__authevent__id__lt=1).annotate(count=Count('loggedevent__pk')) 

    return render_to_response('usage.html', { 
     'ldapusage' : ldapusage, 
     'authusage' : authusage, 
    }, context_instance=RequestContext(request)) 

Tanto ldapusage y authusage son a la vez una lista de usuarios, cada usuario anotado con un atributo .count que se supone que representa el número de eventos particulares que generado por el usuario. Sin embargo, en ambas listas, los atributos .count tienen el mismo valor. De hecho, el 'conteo' anotado es igual a la cantidad de eventos que generó el usuario, independientemente del tipo. Parece que mi específico

authusage = baseusage.exclude(loggedevent__authevent__id__lt=1) 

no se excluye por la subclase. He intentado id__lt = 1, id__isnull = True y otros. Halp.

Respuesta

4

La clave para Django modelo de herencia es recordar que con un no-clase base abstracta todo es realmente una instancia de la clase base que podría pasar a tener algunos datos adicionales atados en el lado de una mesa separada. Esto significa que cuando haces búsquedas en la tabla base obtienes instancias de la clase base y no hay forma de decir qué subclase es sin hacer repetidas consultas de bases de datos en las tablas de subclase para ver si contienen un registro con una clave coincidente ("Tengo un evento. ¿Tiene un registro en AuthEvent? No. ¿Qué pasa con el evento LDAP? ..."). Entre otras cosas, esto significa que no puede filtrar fácilmente en consultas normales en la clase base sin hacer un join en cada tabla de subclase.

Tiene un par de opciones: una sería simplemente hacer sus consultas en la subclase y contar los resultados (ldap_event_count = LDAPEvent.objects.filter(user=foo).count(), ...), lo que podría ser suficiente para un solo informe. Por lo general recomiendo añadir un campo de tipo de contenido a la clase base para que se puede decir de manera eficiente, que subclase particular, un ejemplo es sin tener que hacer otra consulta:

content_type = models.ForeignKey("contenttypes.ContentType")

que permite a dos mejoras principales: la más común es que puede tratar muchos Eventos genéricamente sin tener que hacer algo como golpear los accesores específicos de las subclases (por ejemplo, event.authevent o event.ldapevent) y manejar DoesNotExist. En este caso, también sería trivial reescribir su consulta ya que podría hacer algo como Event.objects.aggregate(Count("content_type")) para obtener los valores del informe, lo que resulta especialmente útil si su lógica se vuelve más complicada ("Evento es Auth o LDAP y ...").

Cuestiones relacionadas