python - framework - install django tastypie
recuperando el final ''muchos'' de una relación de clave externa genérica en Django (2)
Un informe de teletipo tiene muchos pozos y estos pozos se comparten en todos los informes de teletipo. Lo que es diferente es que puedes unir los nodos a los pozos; para un informe de ticker dado, los únicos nodos que deben mostrarse son los que están relacionados con ese informe de ticker.
En Django, cuando solicito un recurso que tiene una relación de muchos a muchos, termino obteniendo todos los elementos en la parte secundaria de la relación, incluso aquellos que no están directamente relacionados con el padre. Será más fácil si te muestro con código (las clases se recortan para mostrar solo lo que es necesario):
Si entiendo correctamente, el nodo puede estar relacionado con el informe o los pozos (porque usted mencionó que está relacionado con ese Informe Ticke ). Y está buscando el nodo relacionado con el informe , no los nodos relacionados con los pozos del informe . (porque está buscando un nodo directamente relacionado con el padre (¿informe?))
Si estoy bien, es bastante simple:
https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#reverse-generic-relations
class Report(models.Model):
name = models.CharField(max_length=255)
slug = AutoSlugField(_(''slug''), populate_from=''name'')
wells = models.ManyToManyField(Well, null=True)
uuid = UUIDField(editable=False, blank=True, version=4, unique=True)
nodes = generic.GenericRelation(Node)
# usage
r = Report.objects.get(id=1)
nodes = r.nodes.all()
En Django, cuando solicito un recurso que tiene una relación de muchos a muchos, termino obteniendo todos los elementos en la parte secundaria de la relación, incluso aquellos que no están directamente relacionados con el padre. Será más fácil si te muestro con código (las clases se recortan para mostrar solo lo que es necesario):
Modelos
class Report(models.Model):
name = models.CharField(max_length=255)
slug = AutoSlugField(_(''slug''), populate_from=''name'')
wells = models.ManyToManyField(Well, null=True)
uuid = UUIDField(editable=False, blank=True, version=4, unique=True)
class Well(models.Model):
slug = AutoSlugField(_(''slug''), populate_from=''name'')
name = models.CharField(max_length=255)
class Node(models.Model):
@property
def well(self):
raise NotImplementedError("The ''well'' field must be implemented")
//irrelevant GFK omitted
page_content_type = models.ForeignKey(ContentType, null=True, blank=True, related_name=''page'')
page_object_id = models.PositiveIntegerField(blank=True, null=True)
page_content_object = generic.GenericForeignKey(''page_content_type'',
''page_object_id'')
Recursos
class ReportResource(ModelResource):
wells = fields.ManyToManyField(WellResource, ''wells'', full=True)
stock = fields.ForeignKey(TickerResource, ''stock'', full=True)
class Meta:
queryset = Report.objects.all()
resource_name = ''ticker_reports''
class WellResource(ModelResource):
nodes = fields.ToManyField(''wells.api.NodeResource'', ''nodes'', full=True)
type = fields.ForeignKey(WellTypeResource, ''type'', full=True)
class Meta:
queryset = Well.objects.all()
resource_name = ''wells''
class NodeResource(ModelResource):
order = fields.IntegerField()
content_object = GenericForeignKeyField({
Content: UUIDOnlyContentResource
}, ''content_object'', full=True)
class Meta:
queryset = Node.objects.all()
resource_name = ''nodes''
filtering = {
''ticker_report'': ALL_WITH_RELATIONS
}
Un informe de teletipo tiene muchos pozos y estos pozos se comparten en todos los informes de teletipo. Lo que es diferente es que puedes unir los nodos a los pozos; para un informe de ticker dado, los únicos nodos que deben mostrarse son los que están relacionados con ese informe de ticker.
Por lo tanto, para un informe de marcador dado y un conjunto de pozos, solo se deben mostrar los nodos que comparten esa GenericForeignKey con ese informe de marcador.
Relaciones
page_object_id
, page_content_object
, page_content_type
es una relación GenericForeignKey con el informe
Actualmente, se muestran todos los nodos (esto es un error).
En TastyPie, ¿cómo le digo que muestre solo los objetos relacionados y no todos los objetos?
Aquí hay una pequeña consola de Python que muestra el problema con mayor sucesión:
>>> r = Report.objects.get(id=1)
>>> for well in r.wells.all():
... for node in well.nodes.all():
... print ''Node in Well {0} is {1}''.format(well, node)
...
Node in Well The Areas You Must Watch (the-areas-you-must-watch - Fancy List) is Apple Content #1:Apple (0)
Node in Well The Areas You Must Watch (the-areas-you-must-watch - Fancy List) is First Solar Content #1:first solar (0)
Node in Well Risks (risks - Headline and Lead) is Apple Content #2:Apple (0)
Node in Well Risks (risks - Headline and Lead) is First Solar Content #2:first solar (0)
>>>
Salida real de SQL
SELECT node.id, node.uuid, node.order,node.content_type_id, node.object_id,
node.page_content_type_id, node.page_object_id, node.well_id FROM node
WHERE node.well_id = 1
ORDER BY node.order ASC
(Modificado para que sea más fácil de leer)
Salida SQL esperada:
SELECT node.id, node.uuid, node.order,node.content_type_id, node.object_id,
node.page_content_type_id, node.page_object_id, node.well_id FROM node
WHERE node.well_id = 1 AND node.page_content_type_id = 99 /*Report Content TypeID */ AND node.page_content_object_id = 1 /*ReportID*/
ORDER BY node.order ASC
Rendimiento esperado:
Node in Well The Areas You Must Watch is Apple Content #1
Node in Well Risks is Apple Content #2:Apple (0)
¿Cómo puedo filtrar el extremo secundario de una relación de muchos a muchos con Django y TastyPie (aunque este problema es evidente sin TastyPie también, lo que me hace creer que es un problema estructural)?
Cuando ejecutas la consulta
well.nodes.all()
esto obtiene todos los nodos que están relacionados con la relación que describió en su modelo.
Parece que desea limitar los nodos devueltos a los que hacen referencia al objeto de Report
r
mediante la relación de clave foránea externa page_content_object
. ¿Está bien? Si lo es, entonces necesitas filtrar los nodos explícitamente, como esto:
r = Report.objects.get(id=1)
for well in r.wells.all():
for node in well.nodes.filter(page_object_id = r.id,
page_content_type = ContentType.objects.get_for_model(r)):
# ...
Actualización: No sé nada acerca de TastyPie y tengo que decir que realmente no entiendo lo que está tratando de hacer, pero en Django, si existe una relación entre los pozos y los nodos, debe agregarla a tus modelos Por ejemplo, si cada Node
pertenece exactamente a un Well
, lo natural sería agregar un campo al modelo de Node
:
class Node(models.Model):
# ...
well = models.ForeignKey(''Well'')
y luego, si desea buscar todos los nodos que pertenecen a pozos que pertenecen a un objeto r
Report
particular, dichos nodos también hacen referencia a r
través de la relación de clave externa genérica, emitiría la consulta:
Node.objects.filter(well__report = r,
page_object_id = r.id,
page_content_type = ContentType.objects.get_for_model(r))
Si tiene que hacer esto mucho, entonces algo natural sería agregar un método en el modelo de Report
.