In Django, when I request a resource that has a many-to-many relationship, I end up getting all the items in child part of the relationship, even those not directly related to the parent. It'll be easier if I show you with code (classes trimmed down to only show what's necessary):
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')
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
}
A Ticker Report has many Wells, and these Wells are shared across all Ticker Reports. What is different is that you can tie Nodes to Wells; for a given ticker report, the only nodes that should display are the ones that are related to that Ticker Report.
So, for a given ticker report and a set of wells, only the nodes that share that GenericForeignKey to that Ticker report should be shown.
Relationships:
page_object_id
,page_content_object
, page_content_type
is a GenericForeignKey relationship to Report
Currently, all Nodes are shown (this is a bug).
In TastyPie, how do I tell it to only show the related objects and not all objects?
Here's a short python console that shows the problem more succicintly:
>>> 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)
>>>
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
(Modified to make it easier to read)
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
Node in Well The Areas You Must Watch is Apple Content #1
Node in Well Risks is Apple Content #2:Apple (0)
How can I filter out the child end of a many-to-many relationship with Django and TastyPie (though this problem is apparent without TastyPie as well, leaving me to believe it's a structural issue)
When you execute the query
well.nodes.all()
this fetches all nodes that are related to well
via the relationship you described in your model.
It sounds as though you want to limit the nodes returned to those that reference the Report
object r
via the page_content_object
generic foreign key relation. Is that right? If it is, then you need to filter the nodes explicitly, like this:
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)):
# ...
Update: I don't know anything about TastyPie and I have to say that I don't really understand what you are trying to do, but in Django, if there is a relation between wells and nodes, then you need to add it to your models. For example, if each Node
belongs to exactly one Well
, the natural thing to do would be to add a field to the Node
model:
class Node(models.Model):
# ...
well = models.ForeignKey('Well')
and then if you want to find all nodes that belong to wells that belong to a particular Report
object r
, said nodes also referencing r
via the generic foreign key relation, you'd issue the query:
Node.objects.filter(well__report = r,
page_object_id = r.id,
page_content_type = ContentType.objects.get_for_model(r))
If you have to do this a lot, then a natural thing to do would be to add a method on the Report
model.
A Ticker Report has many Wells, and these Wells are shared across all Ticker Reports. What is different is that you can tie Nodes to Wells; for a given ticker report, the only nodes that should display are the ones that are related to that Ticker Report.
In Django, when I request a resource that has a many-to-many relationship, I end up getting all the items in child part of the relationship, even those not directly related to the parent. It'll be easier if I show you with code (classes trimmed down to only show what's necessary):
If I understand correctly, the node can be related to report or wells (because you mentioned related to that Ticke Report). And you are looking for the node related to the report, not the nodes related to the wells of the report. (because you are looking for node directly related to the parent(report?) )
If I am correctly, it is quite 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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With