linuxlewis / channels-api Goto Github PK
View Code? Open in Web Editor NEWRESTful Websocket APIs with Django Rest Framework and Channels
License: MIT License
RESTful Websocket APIs with Django Rest Framework and Channels
License: MIT License
How would this package behave with, for e.g. 10 replicas of the same server? (both, rest and some websocket server). If a change goes to server 1, will it be received by a consumer which is listening on server 3?
The socket channel-api works perfectly for one user at one point of time. But when i test it using a forloop, it would simply block the create request. So for the time being the only solution i could find is send one request and wait for 500 seconds. It's working now but i am worried about cases where many user will send create requests at the same point of time then it might miss few orders.
var i = 1;
function myLoop() {
setTimeout(function() {
var conn = new WebSocket('ws://54.238.247.144:5000/');
conn.onmessage = function(e) {
console.log(e.data);
};
var msg = {
stream: "ipad_orders",
payload: {
action: "create",
data: {
"unique_id": "123",
"push_token": "11",
"machine_id": 342,
"machine_name": "ok1",
"parlour": "parlour1",
"total_cost": 333,
"membership": false,
"delivered": false,
"items": "Hello" + i,
"qty": "1",
}
}
}
conn.onopen = () => conn.send(JSON.stringify(msg));
console.log("Sended" + i)
i++;
if (i < 10) {
myLoop();
}
}, 500)
}
myLoop();
Might look like the following:
// get an event when any question is created, updated or deleted
var msg = {
stream: "questions",
payload: {
action: "subscribe",
data: {
action: ["create", "update", "delete"]
}
}
}
Any plans to add the ability to subscribe to every type of action at once?
Thanks
The destroy() method in the DestroyModelMixin for DRF returns HTTP_204_NO_CONTENT whereas the delete() method in DeleteModelMixin here returns 200. It seems this should be consistent and the 204 would be more correct. Am I missing something?
When installing the 0.1.4 version of channels_api I have an error in the dispatch method (generics.py line 31):
self.send(self.format_response(data=super().dispatch(message, **kwargs), message=message))
I change the line 31 by this:
self.send(self.format_response(data=super(ModelConsumerBase, self).dispatch(message, **kwargs), message=message))
And I worked OK
I notice that channels-api requires Py3 to run according to its requirements.
I'm working on a project that may benefit from it, but the project is held into py2.7 stasis due to some remaining work that needs to be done getting twisted's telnet working on Py3.
So I'm thinking of making tweaks to this so it will run on Py2.7 for my own use.
Still learning the differences between Py3 and so I'm just making a simple question here: what specifically in this code does not work with Py2.7?
Currently running pip3 install -r requirements.txt
installs Channels 2.0 which had a massive API overhaul and redesign that causes channels-api to be wholly incompatible. This is causing the current build to be reported as failed.
Since Django Rest Framework is a dependency, why are their permissions classes reimplemented and not just imported?
Hello, I was wondering if is there a way to connect from WebsocketDemultiplexer custome class to postgresql using pgpubsub?. I'm trying to broadcast postgres notifications through WebsocketDemultiplexer, or could you give one solution to achieve this please? I've noted WebsocketDemultiplexer has an own channel and it can't be used with websocket.receive in routing.py
I'm newbie using channels. Thanks in advanced.
I got the following error:
building 'twisted.test.raiser' extension
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
Hi there,
DRF supports HTTP PATCH methods, to support updating a particular part of an existing element. However, within channels-api, they is no such way of updating one field of an object.
Is it possible to create a new resource binding to implement functionality similar to the HTTP PATCH Method?
Channels API is now incompatible with Channels 1.0.2, because of different number of parameters passed to group_names() method. Bug is reproduced by Channels API example. Reproduction:
Additionally, downgrading Channels to 1.0.1 solves the problem.
Hi,
I'm trying to implement authentication using tokens generated by django-rest-framework.
Using this gist: https://gist.github.com/leonardoo/9574251b3c7eefccd84fc38905110ce4
I've managed to do this:
Consumer
class APIDemultiplexer(RestTokenConsumerMixin, WebsocketDemultiplexer):
rest_user = True
def connect(self, message, **kwargs):
Group('users').add(message.reply_channel)
# user here is correct instance of User from given token
print(message.user)
Group('users').send({
'text': json.dumps({
"accepted": "True",
})
})
consumers = {
'campaigns': CampaignBinding.consumer
}
Resource binding
class CampaignBinding(ResourceBinding):
model = Campaign
stream = "campaigns"
serializer_class = CampaignSerializer
queryset = Campaign.objects.all()
permission_classes = (AllowAny,)
def get_serializer_context(self):
# user here is Anonymous
print(self.user)
# I need user instance inside self.message
return {'request': self.message}
My request
ws://localhost:8000/?token=ef0ef25fcfc75c0db91bbbccc062f0ab5786dc34
The thing is that I can access User instance only inside Consumer and User instance is not propagated to ResourceBinding. Is there some obvious way to access ser from token inside ResourceBinding?
Any help would be appreciated.
does it work with py2.7? Or i have to upgrade to py3?
Hi all,
First thanks for this package. It's very much appreciated.
Second, I don't seem to be able to figure out the best way to go about authentication for clients using DRF token based auth. (Django OAuth Toolkit)
Any resource I've found on auth seems to focus on session based auth which I guess makes sense from a websocket point of view.
For my REST api I am sending an Authorization header with an access token as the value. What would you recommend I look into to get this auth working with the channels_api ?
Thank you
Currently when making custom permissions, the "pk" field is useless as there is no way to actually retrieve the instance of the object you are checking against as the BasePermission class has no referent to a model type.
I ran into this issue when trying to write the following permission class to see if a user owns a model:
class IsOwner(BasePermission):
def has_permission(self, user, action, pk):
try:
# have to hard code Job here because BasePermission has no reference to the Model it is checking
job = Job.objects.get(pk=pk)
except Job.DoesNotExist:
return False
if action == "SUBSCRIBE":
return user == job.owner
return False
While this works for the Job model, I want to make this more general as I have other models with Owner that I want to use the same permission on. As I see it now, there's no way to generically use this field to do anything at all.
I think this was just a design oversight and I figure this can be solved pretty easily through just passing a reference to the Model of the binding to the permission class upon construction that can then be accessed from the has_permission method. I'll submit a PR with a fix once I have a chance.
Great work man! Any progress / thoughts on permissions? From that point forward it will become useful for me.
Was there a Channel's tutorial that was based on the Django Poll's tutorial at some point ?
Hi there,
Currently, the subscriptions only allow subscriptions for any resource, or a specific resource by it's PK. Is it possible to implement functionally to subscribe to a set of resources that fulfil some criteria, other than PK.
For example, we might have a field called name, and we may want to subscribe to any creations in which the name == "John". The current work around is to subscribe for all creations, and then filter the stream client side.
Just an example of how this could be done
{
"stream": "people",
"payload": {
"action":"subscribe",
"data": {
"action": "create"
}
"filter":{
"name": "John"
}
}
It would probably also make sense to move the existing PK field to the new filter dict.
This is obviously a big design change, but I personally feel that keeping as much of the processing on the server side is better than the current workaround.
I am getting this error after I updated the package
2017-06-01 02:16:22,002 - ERROR - worker - Error processing message with consumer faceoff_api.routing.APIDemultiplexer:
Traceback (most recent call last):
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/worker.py", line 119, in run
consumer(message, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/generic/base.py", line 32, in __init__
self.dispatch(message, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/generic/base.py", line 70, in dispatch
return self.get_handler(message, **kwargs)(message, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/generic/websockets.py", line 154, in raw_receive
self.receive(self.decode_json(message['text']), **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/generic/websockets.py", line 266, in receive
consumer(self.message, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/binding/base.py", line 240, in consumer
handler(message, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/sessions.py", line 78, in inner
return func(*args, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/auth.py", line 42, in inner
return func(message, *args, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/binding/websockets.py", line 90, in trigger_inbound
super(WebsocketBinding, cls).trigger_inbound(message, **kwargs)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels/binding/base.py", line 222, in trigger_inbound
self.run_action(self.action, self.pk, self.data)
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels_api/bindings.py", line 145, in run_action
if not self.has_permission(self.user, action, pk):
File "/Users/coreytrombley/.envs/faceoff_venv/lib/python3.5/site-packages/channels_api/bindings.py", line 111, in has_permission
if not cls().has_permission(user, action, pk):
TypeError: has_permission() takes 3 positional arguments but 4 were given
Hi, linuxlewis.
I think it's question to you ..
I have the trouble with authorization based on this package:
https://github.com/GetBlimp/django-rest-framework-jwt
If i try to do normal ajax request to collection /questions i get errors:
HyperlinkedIdentityField
requires the request in the serializer context. Add context={'request': request}
when instantiating the serializer.
So .. ok. That's can be good for me, i would change all application logic for use websockets and it's not problem for me.
But when i try to send request with ws.send(JSON.stringify(msg)):
var msg = { stream: "questions", payload: { action: "create", data: { description: "What is your favorite python package?", categories: ["http://localhost:8000/api/categories/1/"] }, request_id: "some-guid" } } ws.send(JSON.stringify(msg))
I get this error:
IntegrityError: null value in column "owner_id" violates not-null constraint
DETAIL: Failing row contains (11, 2017-06-11 12:06:02.583387+00, What is your favorite python package?, , 1200.00000000, f, f, f, null).
My QuestionSerializer looks like:
`class QuestionSerializer(serializers.HyperlinkedModelSerializer):
def create(self, validated_data):
categories_data = validated_data.pop('categories')
question = Question.objects.create(**validated_data)
question.is_open = True
question.is_finish = True
question.save()
for category in categories_data:
question.categories.add(category)
return question
owner = UserSerializer(read_only=True)
answers = AnswerSerializer(many=True, read_only=True)
elo = serializers.ReadOnlyField()
is_verified = serializers.ReadOnlyField()
is_finish = serializers.ReadOnlyField()
is_open = serializers.ReadOnlyField()
class Meta:
model = Question
fields = (
'url',
'id',
'created',
'owner',
'description',
'elo',
'is_verified',
'is_finish',
'is_open',
'categories',
'answers'
)`
The model:
`class Question(models.Model):
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(
'auth.User',
related_name='%(app_label)s_%(class)s_related'
)
categories = models.ManyToManyField(
'core.Category'
)
answers = models.ManyToManyField(
'learn.Answer'
)
description = models.TextField()
additional = models.TextField()
elo = models.DecimalField(
max_digits=20,
decimal_places=8,
default=Decimal('1200.0000')
)
is_verified = models.BooleanField(
default=False
)
is_finish = models.BooleanField(
default=False
)
is_open = models.BooleanField(
default=False,
blank=True
)
def __unicode__(self):
return self.description`
And view:
`class QuestionViewSet(viewsets.ModelViewSet):
serializer_class = QuestionSerializer
permissions_classes = (
IsOwnerOrReadOnly,
)
def get_queryset(self):
queryset = Question.objects.all()
category = self.request.query_params.get('category', None)
description = self.request.query_params.get('description', None)
if description is not None:
queryset = Question.objects.filter(description__icontains=description)
if category is not None and description is None:
is_verified = self.request.query_params.get('is_verified', None)
is_finish = self.request.query_params.get('is_finish', None)
if is_verified is not None and is_finish is not None:
queryset = Question.objects.filter(categories__pk=category, is_verified=True, is_finish=True)
else:
queryset = Question.objects.filter(categories__pk=category)
if category is not None and description is not None:
queryset = Question.objects.filter(categories__pk=category, description=description)
return queryset
def perform_create(self, serializer):
serializer.save(owner=self.request.user)`
Can you explain me how can i get it works all together?
Basicly i need to create only private chat for this moment for my users but i trying to understand how can i make other stuff in application with channels_api and this crap won't let me fall a sleep...
Thank you for your attention and suggestion if you know how i can resolve this problem.
Hi All, I installed the package through pip and it seems to be missing the decorator module.
python3.4/site-packages/channels_api contains; bindings.py, mixins.py, settings.py, urs.py etc but no decorators.py
env; python 3.4, django 1.11, DRF 3.6
If you don't use the default django primary key for your models and instead use "ID = models.AutoField(primary_key=True)" for example there are two problems.
Firstly id = instance.id in the bindings.py will throw an error because you don't have the id field. Can apparently be fixed by replacing it with id = instance.pk
Secondly if you send a "create" message through a websocket it will complain that the field "ID" is required.
Are you sure that the following
// get an event when question(1) is updated
var msg = {
stream: "questions",
payload: {
action: "subscribe"
data: {
action: "update",
pk: "1"
}
}
}
shouldn't be
// get an event when question(1) is updated
var msg = {
stream: "questions",
payload: {
action: "subscribe",
pk: "1",
data: {
action: "update"
}
}
}
instead? (BTW, there is also a syntax error.)
From our testing this seems to be the case.
Since channels project dropped Bindings from base package due it's simplistic design - this is a great opportunity to implement them within this project and keep this project relevant.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.