2012-09-17 17 views
6

me encontré con un modelo como este:¿Cómo puedo usar el objeto F() para hacer esto con el ORM de Django?

class Task(models.Model): 
    timespan = models.IntegerField(null=True, blank=True) 

class Todo(models.Model): 
    limitdate = models.DateTimeField(null=True, blank=True) 
    task = models.ForeignKey(Task) 

necesito para extraer todo Todos con un limitdate que es menor o igual a la fecha de hoy + un intervalo de tiempo definido en el modelo Task relacionados.

Algo así (ejemplo ficticio):

today = datetime.datetime.now() 
Todo.objects.filter(limitdate__lte=today + F('task__timespan')) 

Ahora, puedo hacer eso con un lazo pero estoy buscando una manera de hacerlo con F(), y no puedo encontrar uno.

Estoy empezando a preguntarme si puedo hacer eso con F(). Tal vez debería usar extra?

Tenga en cuenta que no tengo el lujo de cambiar el código del modelo.

+0

No probado, pero si task__timespan sería un timedelta, debería funcionar, ¿no puede agregar una función al modelo de tareas que devuelve self.timespan como timedelta? –

+0

Estoy bastante seguro de que Django no te permite filtrar los resultados del método ;-) Incluso con un campo personalizado, no veo cómo se podría traducir esto a SQL. –

+0

Por supuesto, tienes razón, tbh No creo que sea posible con F sin hackearlo –

Respuesta

2

El problema es que no hay un tipo TIMESPAN en una base de datos. Por lo tanto, F no puede devolver algo con lo que realmente pueda trabajar en este contexto. No estoy seguro de qué tipo de campo usó realmente en su base de datos, pero la única forma en que puedo pensar para hacer esto es almacenar el intervalo de tiempo como un número entero compuesto por segundos, agregar eso a "hoy" como una marca de tiempo, y luego conviértalo de nuevo a una fecha y hora que puede usar para compararlo con limitdate. Sin embargo, no estoy seguro si Django aceptará una lógica tan compleja con F.

+0

Voy a elegir esto, haciendo un cúspide IntegerField que aceptará fechas y marcas de tiempo de la tienda. –

4

El principal problema es que DB no admite date + integer y es difícil de escribir consulta ORM a date + integer::interval, para PostgreSQL por ejemplo, donde integer es el valor de la columna de task_timespan, en días recuento.

Sin embargo, como
limitdate <= today + task__timespan es igual a
limitdate - today <= task__timespan

Podríamos transformar la consulta a

Todo.objects.filter(task__timespan__gte=F('limitdate') - today).distinct()

así el SQL se convierte en algo así como integer >= date - date, que debería funcionar en PostgreSQL porque date - date salidas interval que podría ser comparado con integer días.

En otras DB como SQLite, esto es complicado debido a las fechas tienen que ser echado w/julianday() al principio ... y creo que se necesita para jugar w/extra()raw() o incluso para obtener el SQL correcto.

Además, como sugiere Chris Pratt, si pudiera usar la marca de tiempo en todos los campos relativos, la tarea de consulta podría ser más fácil debido a las operaciones de suma y resta menos limitadas.

P.S. No tengo env para verificarlo ahora, puedes probarlo primero.

+0

¡es asombroso! 'F ('limitdate') - today' funciona en PostgreSQL! acaba de probar un caso similar. ¡Gracias! – fjsj

+0

malvadamente inteligente respuesta! gracias @okm! –

Cuestiones relacionadas