Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Can't override get_queryset method when using ObserverModelInstanceMixin and GenericAsyncAPIConsumer #166

Open
erdos4d opened this issue Mar 13, 2023 · 3 comments

Comments

@erdos4d
Copy link

erdos4d commented Mar 13, 2023

I'm following the example in the docs here using ObserverModelInstanceMixin and GenericAsyncAPIConsumer to set up a subscriptions view on certain model instances that clients have interest in. I have a "real world" permission situation and I need to override the get_queryset method to return a different queryset depending on who is requesting what. When I do this, I get the stack trace I posted below in the LOG section. This happens even if I return the stock SomeModel.objects.all() from the method. It looks like it wants a ModelObserver object to call subscribe on, but gets a _GenericModelObserver instead. This works fine when I just define the queryset attribute like in the example, so I am guessing there is some sort of dynamic class building going on somewhere and overriding the method throws that off.

To Reproduce
Follow the example given in the docs, delete the queryset attribute and override the get_queryset method to return the same queryset.

Expected behavior
It works and you get the new queryset behavior you coded up.

LOG
File "/.venv/lib/python3.10/site-packages/django/contrib/staticfiles/handlers.py", line 101, in call
return await self.application(scope, receive, send)
File "/.venv/lib/python3.10/site-packages/channels/routing.py", line 62, in call
return await application(scope, receive, send)
File "/.venv/lib/python3.10/site-packages/channels/security/websocket.py", line 37, in call
return await self.application(scope, receive, send)
File "/scheduler/middleware.py", line 29, in call
return await self.app(scope, receive, send)
File "/.venv/lib/python3.10/site-packages/channels/routing.py", line 116, in call
return await application(
File "/.venv/lib/python3.10/site-packages/channels/consumer.py", line 94, in app
return await consumer(scope, receive, send)
File "/.venv/lib/python3.10/site-packages/channels/consumer.py", line 58, in call
await await_many_dispatch(
File "/.venv/lib/python3.10/site-packages/channels/utils.py", line 50, in await_many_dispatch
await dispatch(result)
File "/.venv/lib/python3.10/site-packages/channels/consumer.py", line 73, in dispatch
await handler(message)
File "/.venv/lib/python3.10/site-packages/channels/generic/websocket.py", line 194, in websocket_receive
await self.receive(text_data=message["text"])
File "/.venv/lib/python3.10/site-packages/channels/generic/websocket.py", line 257, in receive
await self.receive_json(await self.decode_json(text_data), **kwargs)
File "/.venv/lib/python3.10/site-packages/djangochannelsrestframework/consumers.py", line 197, in receive_json
await self.handle_action(action, request_id=request_id, **content)
File "/.venv/lib/python3.10/site-packages/djangochannelsrestframework/consumers.py", line 192, in handle_action
await self.handle_exception(exc, action=action, request_id=request_id)
File "/.venv/lib/python3.10/site-packages/djangochannelsrestframework/consumers.py", line 152, in handle_exception
raise exc
File "/.venv/lib/python3.10/site-packages/djangochannelsrestframework/consumers.py", line 185, in handle_action
response = await method(request_id=request_id, action=action, **kwargs)
File "/.venv/lib/python3.10/site-packages/djangochannelsrestframework/observer/generics.py", line 98, in subscribe_instance
groups = set(await self.handle_instance_change.subscribe(instance=instance))
AttributeError: '_GenericModelObserver' object has no attribute 'subscribe'

I'm running ubuntu 22.04.

Additional context
I'm willing to put a PR in but I honestly find the code a bit confusing. Many things seem named the same and use decorators for inheritance, which I am honestly not used to. If someone has an idea what is wrong I will try though.

@hishnash
Copy link
Member

hishnash commented Apr 8, 2023

Hi @erdos4d thank you for reporting this you should absolutly be able to override the get_queryset method... through in my examples I tend to use fitler_queryset (that should work)

just to be clear the intention here is to filter what a user can subscribe to ? or is the intention to filter the results from REST like actions: list retrieve create and update etc?

@hishnash
Copy link
Member

hishnash commented Apr 8, 2023

So I have done a little more looking into this and the source of the issue is

The reason this is here is we need to register a django even hook on the database record. (this needs to happen before any insurance of the consumer is created but rather when django starts up) so we cant use get_queryset as this is an instance method and we need to be able to know the DB record type at django startup to register change handlers on all running threads/instrances of django.

you can use filter_queryset method (as used here https://nilcoalescing.com/blog/BuildingARealtimeSocialNetworkUsingDjangoChannels/#websocket-consumer ) to filter based on the user (however as that post describes this has limited use for subscription in that case you need to follow the suggestions in the post by defining the groups that are used to notify of changes and limiting what groups a user can subscribe to).

@hishnash
Copy link
Member

hishnash commented Apr 8, 2023

this mixin should realy check if get_queryset has been defined and if it has it should raise some warning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants