0

The Django docs are not very clear on how to filter objects such that they contain a filtered subset of related fields.

Suppose I have the following models:

class Device(models.Model):
    name = models.CharField(max_length=50)

class DeviceEvent(models.model):
    device=models.ForeignKey(Device, null=False, related_name='device_events')
    handled = models.BooleanField(default=Fasle)

Now suppose I want to retrieve a list of all Devices that have unhandled DeviceEvents. How can I write a query in Django to do that?

The end result should be devices where devices is a list of Device objects, and for each device object "device" we have device.device_events is the list of unhandled DeviceEvent objects. Is this possible to do in Django?

Or, can I do it in python like this:

all_devices=Device.objects.all()
devices=[]
for thedevice in all_devices:
    unhandled_device_events=thedevice.device_events.\
                                      annotate(num_events=Count('device_events')).\
                                      filter(device_event__device=thedevice).\
                                      filter(num_events__gt=0).\
                                      filter(device_event__handled=False).all()
    if unhandled_device_events:
        thedevice.device_events=unhandled_device_events
        devices.append(thedevice)

In the above I am creating a new list called devices, then looping through all Device objects and manually adding a device to devices only if it has at least one unhandled event, AND that device object now has device.device_events=the unhandled device events (not ALL the device events). Is this allowed or at all efficient?

Or when I refer to one of the device_events as "device_event" and not "deviceevent" which is correct?

Marc
  • 3,386
  • 8
  • 44
  • 68

3 Answers3

0

If I understood correctly your question, I think this should work

Device.objects.get(Device.device_events.handled = False)
Mihai Zamfir
  • 2,167
  • 4
  • 22
  • 37
0

Since it's a ForeignKey relationship, I believe you can grab all of the DeviceEvents keyed to a device with this (assume d is an instance of the Device class):

d.deviceevent_set.all()

You should be able to filter that like so:

d.deviceevent_set.filter(handled=False)

I haven't tested this but I think it'll work.

Edit: after reading your comment I realize that I failed to read your question as closely as I thought I had.

You could use the code above in a for loop after you pull out the device you want. Get your device instance, then grab the unhandled events associated with that device using this snippet. For example, iterate though everything in device.objects.all() and check to see if d.device_set.filter(handled=false) returns anything for each device. If it does, perhaps you could add that device to a dictionary as a key and a list of unhandled events as the associated value. You'll end up with a dictionary of device[unhandledevents]. This post could tell you more about that if you want.

Would you be able to manipulate the data in the ways you need from there, or am I off base with what you're looking for?

Community
  • 1
  • 1
souldeux
  • 3,615
  • 3
  • 23
  • 35
0

Try this

d = Device.objects.filter(device_events__handled=False)
gwaramadze
  • 4,523
  • 5
  • 30
  • 42