2012-10-01 14 views
8

Disculpe si mi pregunta resulta ser una tontería, pero soy bastante nuevo en Django y no pude encontrar una respuesta en ningún lado.Modelos de Django: asignar ID en lugar de objeto

tengo el siguiente modelo:

class BlackListEntry(models.Model): 
    user_banned = models.ForeignKey(auth.models.User,related_name="user_banned") 
    user_banning = models.ForeignKey(auth.models.User,related_name="user_banning") 

Ahora, cuando intento para crear un objeto como éste:

BlackListEntry.objects.create(user_banned=int(user_id),user_banning=int(banning_id)) 

me sale un error de seguimiento:

Cannot assign "1": "BlackListEntry.user_banned" must be a "User" instance. 

De Por supuesto, si lo reemplazo con algo como esto:

user_banned = User.objects.get(pk=user_id) 
user_banning = User.objects.get(pk=banning_id) 
BlackListEntry.objects.create(user_banned=user_banned,user_banning=user_banning) 

todo funciona bien. La pregunta es:

¿Mi solución golpea la base de datos para recuperar ambos usuarios y, en caso afirmativo, es posible evitarla, simplemente al pasar los identificadores?

Respuesta

10

La respuesta a su pregunta es: SÍ.

Django golpeará la base de datos (al menos) 3 veces, 2 para recuperar los dos objetos de usuario y un tercero para confirmar la información deseada. Esto causará una sobrecarga innecesariamente absoluta.

sólo trato:

BlackListEntry.objects.create(user_banned_id=int(user_id),user_banning_id=int(banning_id)) 

ellos es el patrón de nombre por defecto para los campos generados por FK ORM de Django. De esta forma puede establecer la información directamente y evitar las consultas.

Si quería para consultar los objetos BlackListEntry ya guardados, se puede navegar los atributos con un doble subrayado, así:

BlackListEntry.objects.filter(user_banned__id=int(user_id),user_banning__id=int(banning_id)) 

Así es como se accede a las propiedades en QuerySets Django. con un doble guion bajo Entonces puedes comparar con el valor del atributo.

Aunque son muy similares, funcionan completamente diferente. El primero establece un atributo directamente mientras que el segundo es analizado por django, que lo divide en '__', y consulta la base de datos de la manera correcta, siendo la segunda parte el nombre de un atributo.

Siempre puede comparar user_banned y user_banning con los objetos de usuario reales, en lugar de sus identificadores. Pero no sirve de nada si todavía no tienes esos objetos contigo.

Espero que ayude.

+0

Esto me da: 'user_banning__id' es un argumento de palabra clave no válido para esta función –

+0

Lo siento, me acabo de dar cuenta de que está creando el objeto. Por lo tanto, debe acceder con un solo guion bajo. Editaré mi respuesta para explicar por qué. – Francisco

+0

Gracias, ahora funciona. Te agregaría +1, pero estoy demasiado listo para hacerlo todavía. –

0

yo creo que al recuperar los usuarios, que va a golpear el PP ...

Para evitarlo, se tendría que escribir el código SQL prima para hacer la actualización usando el método descrito aquí:

https://docs.djangoproject.com/en/dev/topics/db/sql/

Si decide ir por ese camino que tener en cuenta que es responsable de proteger a sí mismo de los ataques de inyección SQL.

Otra alternativa sería almacenar en caché los objetos user_banned y user_banning.

Pero con toda probabilidad, simplemente agarrar a los usuarios y crear BlackListEntry no le causará ningún problema de rendimiento notable. El almacenamiento en caché o la ejecución de sql en bruto solo proporcionará un pequeño beneficio. Probablemente te encuentres con otros problemas antes de que esto se convierta en un problema.

Cuestiones relacionadas