Monday, October 28, 2019

search results from a Django model method including the results from earlier calls to the same method (x post StackOverflow)

I also posted this to SO 
https://stackoverflow.com/questions/58600159/search-results-from-a-django-model-method-including-the-results-from-earlier-cal
hope that's ok, let me know if not.

I have a Django Model that tracks email message IDs as the message passes through different servers. It has a models.ForeignKey field to itself, so we can chain them together to follow the full path of a message through many servers. 

The model has a 'get_children()' method that recursively looks for all messages descended from the given message.

    class Relay(models.Model):
        hostname = models.CharField(max_length=48)
        qid = models.CharField(max_length=24)
        received_from = models.ForeignKey(
            "self",
            blank=True,
            null=True,
            default=None,
            on_delete=models.SET_DEFAULT
        )
        def get_children(self, parent_messages=set()):
            for r in Relay.objects.filter(received_from=self):
                r.get_children(parent_messages)
            parent_messages.add(self)
            p = list(parent_messages)
            parent_messages = set()
            return p
       

If I run a single query from the Django shell, it works as expected. "Solo" messages return only themselves. Messages with multiple child/descendant messages are found as well.

    >>> r = Relay.objects.get(qid='xo2')
    >>> r.get_children()
    [<Relay: server2 foo>, <Relay: server3 bbb>, <Relay: server1 xo2>]

If I kill and restart the shell, the next query works as expected, fetching a single message

    >>> r = Relay.objects.get(qid='singletonMsg')
    >>> r.get_children()
    [<Relay: server5 singletonMsg>]

But if I run get_children() repeatedly within a single Django shell session, it always includes the results of the previous get_children() calls.
   
    >>> r = Relay.objects.get(qid='singletonMsg')
    >>> r.get_children()
    # expected result
    [<Relay: server5 singletonMsg>]  
    >>>
    >>> r = Relay.objects.get(qid='xo2')
    >>> r.get_children()
    # unexpected result - should not include singletonMsg 
    [<Relay: server2 foo>, <Relay: server3 bbb>, <Relay: server5 singletonMsg>, <Relay: server1 xo2>]
    >>>
    >>> r = Relay.objects.get(qid='singletonMsg')
    >>> r.get_children()
    # unexected result - should just return singletonMsg ??
    [<Relay: server2 foo>, <Relay: server3 bbb>, <Relay: server5 singletonMsg>, <Relay: server1 xo2>]


I was originally returning the "parent_messages" set from the function. I tried 
    return [m for m in parent_messages]
and the current list() thinking it was a closure issue, but no luck.
I am stumped. Thanks in advance for any advice.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/84bc2c30-9186-4005-b6c3-530896619eb4%40googlegroups.com.

No comments:

Post a Comment