Re: need to support anonymous users with a simple one time disclaimer agreement

2019-08-04 Thread Ken Whitesell
Gregory,

 Not only is it not practical in Django, it's not a realistic solution 
using any framework. 

There is no "machine ID" that is exposed to a web site, and originating IP 
addresses completely fails for all people accessing your site from behind a 
NAT box or other similar functional device. (I work in an office using a 
private ip address range - 10.1.xxx.xxx. All websites that any of us access 
all see the same originating IP address. So if I were to acknowledge that 
disclaimer, your software would assume that everyone in my office has done 
that - which I don't think you want.)

Yes, there are some options that would cover most of the common cases - you 
could use a cookie for example, to track on the user's side whether or not 
they've agreed to that disclaimer. That'll work for as long as they keep 
the cookies and don't change browsers - or run in incognito mode.

(And all of this is discounting any intentional actions to spoof / avoid 
that disclaimer.)

If you have any _real_ requirement for that disclaimer to be acknowledged, 
then an actual per-user account is the only way to do it.

Ken



On Saturday, August 3, 2019 at 10:08:35 AM UTC-4, Gregory Hines wrote:
>
> I am an experienced software developer but new to django.  I am trying to 
> create a simple website in which each new user (either based on their IP 
> address or even more specific machine ID) would be asked to agree to a 
> simple disclaimer before going on to access the site. On subsequent usage I 
> don't want them to be offered the same disclaimer and repeat user should be 
> sent directly to the main page of the website.
>
> I am using TemplateViews  and  basic templates that offer up form that the 
> user fills and submits.  I specifically don't want each user to have to 
> establish a ogin acct etc.  Is this possible w/ django? 
>
> Any and all hints welcome.
>
>
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/672dfc54-5b11-4bc9-b7f5-f44d68452b83%40googlegroups.com.


Re: How to use permissions on a CreateView class?

2019-05-29 Thread Ken Whitesell
Fellipe,

In addition to the permissions_required variable, I believe you also need 
to include the PermissionsRequired mixin in your class definition:

https://docs.djangoproject.com/en/2.2/topics/auth/default/#the-permissionrequiredmixin-mixin

Ken

On Tuesday, May 28, 2019 at 5:54:39 PM UTC-4, Fellipe Henrique wrote:
>
> Hi Jim, 
>
> Tried that, as you can see on my code, but not working.. when user type 
> the url, still see the template..
>
> Any suggestions?
>
> Regards,
>
> T.·.F.·.A.·. S+F
> *Fellipe Henrique P. Soares*
>
> e-mail: > echo "lkrrovknFmsgor4ius" | perl -pe \ 
> 's/(.)/chr(ord($1)-2*3)/ge'
> *Fedora Ambassador: https://fedoraproject.org/wiki/User:Fellipeh 
> *
> *Blog: *http:www.fellipeh.eti.br
> *GitHub: https://github.com/fellipeh *
> *Twitter: @fh_bash*
>
>
> On Tue, May 28, 2019 at 2:36 PM Jim Illback  > wrote:
>
>> I think you can also add to your class (right under your *template_name*… 
>> for example) this statement: 
>>
>>  permission_required = *‘*appname.permission_name'
>>
>> This will limit to logged on users (as below), and also to users who possess 
>> this permission.
>>
>> Jim
>>
>>
>> On May 28, 2019, at 9:55 AM, Joe Reitman > > wrote:
>>
>> Fellipe, 
>>
>> Here is an example of decorating class based views from the documentation 
>> 
>> :
>>
>> from django.contrib.auth.decorators import login_requiredfrom 
>> django.utils.decorators import method_decoratorfrom django.views.generic 
>> import TemplateView
>> class ProtectedView(TemplateView):
>> template_name = 'secret.html'
>>
>> @method_decorator(login_required)
>> def dispatch(self, *args, **kwargs):
>> return super().dispatch(*args, **kwargs)
>>
>>
>> On Tuesday, May 28, 2019 at 6:54:38 AM UTC-5, Fellipe Henrique wrote: 
>>>
>>> Hello, 
>>>
>>> I have these class, based on CreateView class... and I only want allow 
>>> user with these permissions to add record...
>>>
>>> class ClienteCreateView(ERPbrViewMixin, CreateView):
>>> template_name = 'cadastro/cliente/form.html'
>>> permission_required = ('cliente.can_open', 'cliente.can_edit', 
>>> 'cliente.can_add')
>>> model = Cliente
>>> form_class = ClienteForm
>>>
>>> But, not working... user without these permission, when type the url 
>>> show the form...
>>>
>>> Any tips how to do that?
>>>
>>> Cheers!
>>>
>>>
>>> T.·.F.·.A.·. S+F
>>> *Fellipe Henrique P. Soares*
>>>
>>> e-mail: > echo "lkrrovknFmsgor4ius" | perl -pe \ 
>>> 's/(.)/chr(ord($1)-2*3)/ge'
>>> *Fedora Ambassador: https://fedoraproject.org/wiki/User:Fellipeh 
>>> *
>>> *Blog: *http:www.fellipeh.eti.br 
>>> *GitHub: https://github.com/fellipeh *
>>> *Twitter: @fh_bash*
>>>
>>
>> -- 
>> 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...@googlegroups.com .
>> To post to this group, send email to djang...@googlegroups.com 
>> .
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-users/060a2c59-bf39-456c-a686-bf6ba104e1f7%40googlegroups.com
>>  
>> 
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>> -- 
>> 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...@googlegroups.com .
>> To post to this group, send email to django...@googlegroups.com 
>> .
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-users/B5E64E45-C1C3-455F-AEC7-167852FE17C7%40hotmail.com
>>  
>> 
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/807b9db0-7dcd-4c42-b1e0-430655352056%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: how handle high incoming data and sending throttled data to web sockets in django-channels

2019-01-15 Thread Ken Whitesell
We deal with a similar rate of data acquisition, and have taken a different 
approach. (We get, on average, about 10,000,000 UDP messages / day)

We have a very small UDP listener (about 50 lines of Python 3 code), and 
_all_ it does is receive the message and dump it into a Celery queue. We 
then run multiple Celery worker tasks to process that data and write it to 
the database.

There are some times during peak period in the day where the queue might 
get backed up 1,000,000 messages or so, but we never have any problems 
getting them all processed that day. (UDP packets effectively stops around 
9 PM.)

We may be losing some packets - with UDP, how can you tell? But the numbers 
of packets processed are well within 95% of projections, and so for our 
purposes it's quite satisfactory.
(There is absolutely no way for us to determine if some upstream device is 
being saturated and dropping packets that we should otherwise be receiving. 
Or more accurately, how many packets are being dropped upstream from our 
collection point. UDP is definitely not the protocol to be using if you 
absolutely need to receive 100% of your data.)

On Monday, January 14, 2019 at 9:31:21 AM UTC-5, Sahil Mangotra wrote:
>
> I am facing a problem in my django web server.
>
> We are using python3, django2, django-rest-framework3.8 and channels2.x
>
> Scenario is we are receiving DATA from a UDP connection at very fast rate 
> (~100 messages per second). The data revived is in proto format (you can 
> say we are receiving byte data). some data gets starved in this process as 
> *Rate 
> of production >>> rate of consumption* we are implementing throttling but 
> still at 100 concurrent users data starves again. Can anyone help us in 
> this scenario.
>
> If anyone has any new architecture idea please share.
>
> *This is surely an interesting problem. This is about stock market feed*
>
> PS :- I cannot post any code as it is my companies. but i can help any 
> time you need clarification on any point.
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/55ca74e0-1164-40cc-90a0-7e1e1b0baad3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Nullable vs empty strings

2018-05-03 Thread Ken Whitesell
Nick,

 A null string (string with length 0) is _not_ the same as a null field 
(no string). The two are distinct, and (can) serve two very different 
functions. 

Take a look at this for some more detailed 
information: 
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value

Ken


On Thursday, May 3, 2018 at 5:17:35 AM UTC-4, Nick Sarbicki wrote:
>
> I just saw this in the docs: 
> https://docs.djangoproject.com/en/2.0/ref/models/fields/#null
>
> Suggesting that you should never set a CharField to null unless using a 
> unique index.
>
> Is this generally accepted? Historically I've always nulled a CharField 
> because using empty strings, as opposed to letting a column be nullable, 
> has felt very dirty to me.
>
> I would have expected (not suggesting this as a change) an empty string to 
> fail if the field isn't nullable.
>
> Am I on my own here?
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/23e3a4dc-345a-4fb9-8122-0dba7b99bb4d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Multiple websocket connection vs single websocket connection when using django channels

2018-04-06 Thread Ken Whitesell
Hi Robin,

I can't speak to any generalized situations, or what might be considered 
"best practices" or most optimal.

What I can say is that we have gone with the single websocket connection 
for each client - whether it's a real person at a browser or an 
application. All our communications through the channel are JSON objects, 
and we include a key named "app" in the object which identifies the 
specific "feature" or "application" to which a message is directed. It's 
done in both directions - submissions through the channel from the browsers 
to the server and from the server to the browser all have that key in the 
JSON. 

About the most I can say is that it works well for us. 

Ken

On Friday, April 6, 2018 at 5:10:41 AM UTC-4, Robin Lery wrote:
>
> Hi,
>
> Suppose an application has features like Chat, Notification and Activity 
> feeds. 
>
> I would like to know whether its recommended to have different   websocket 
> connection for different  feautues for each user. Meaning for chat purpose 
> a separate socket connection, for notification another separate connection?
>
> Or is it better to have only one websocket connection for a user, and work 
> around that single connection for different features?
>
> Sincerely,
> Robin 
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/0bf0d083-1bb3-4963-905c-9e8bfce6c765%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: How to run an external command that must run with the server

2018-04-03 Thread Ken Whitesell
There's an aspect of your situation which isn't entirely clear to me - is this 
management command one that remains running all the time, like a Celery task 
would be; or is it one that starts, runs a process for a period of time, and 
then ends - only to be restarted at a later time? If the former, then yes, 
running the management command from supervisor makes sense to me. If the 
latter, then I'd probably be looking at doing something different.


Ken


> On April 3, 2018 at 6:15 AM 'Alex' via Django users 
> <django-users@googlegroups.com> wrote:
> 
> That makes sense. So leave the source as a management command (as it is 
> now), and just run python manage.py source through supervisor?
> 
> 
> On Sunday, 1 April 2018 13:16:38 UTC+1, Ken Whitesell wrote:
> 
> > > We set up all our Django-related processes as a group 
> under supervisor. This includes our celery-based processes. (We have some 
> long-running tasks that are kicked off by the web site.) By setting it up as 
> a group, we can manage all the different processes as a set.
> > 
> > Whether or not that's the "best" way is possibly debatable. But it 
> > works for us and doesn't give us any problems.
> > 
> > Ken
> > 
> > On 4/1/2018 7:06 AM, 'Alex' via Django users wrote:
> > 
> > > > > I have a daphne server running a django 
> > channels application. I also have a python script that aggregates data from 
> > various sources, and sticks it into the channel layer (called source.py). 
> > At the moment, I run it as a management command (python manage.py source). 
> > It is nearly time for deployment(!), so I'm moving towards production 
> > solutions. Daphne itself currently runs under supervisor.
> > > 
> > > My question is, what is the best way to run source.py? As a 
> > > management command, also under supervisor? Using celery? In some other 
> > > way? Since source.py feeds into the channel layer, it needs access to 
> > > settings.py in order to identify the details of the channel layer etc.
> > > --
> > > 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...@googlegroups.com.
> > > To post to this group, send email to 
> > > django...@googlegroups.com.
> > > Visit this group at 
> > > https://groups.google.com/group/django-users 
> > > https://groups.google.com/group/django-users .
> > > To view this discussion on the web visit 
> > > https://groups.google.com/d/msgid/django-users/b3c22939-b520-4c9c-90f9-ef8cb7b8c661%40googlegroups.com
> > >  
> > > https://groups.google.com/d/msgid/django-users/b3c22939-b520-4c9c-90f9-ef8cb7b8c661%40googlegroups.com?utm_medium=email_source=footer
> > >  .
> > > For more options, visit https://groups.google.com/d/optout 
> > > https://groups.google.com/d/optout .
> > > 
> > > > > 
> > 
> > > 
>  
> 
> --
> 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+unsubscr...@googlegroups.com 
> mailto:django-users+unsubscr...@googlegroups.com .
> To post to this group, send email to django-users@googlegroups.com 
> mailto:django-users@googlegroups.com .
> Visit this group at https://groups.google.com/group/django-users.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/django-users/432d449c-d089-43cd-a739-702847729b6b%40googlegroups.com
>  
> https://groups.google.com/d/msgid/django-users/432d449c-d089-43cd-a739-702847729b6b%40googlegroups.com?utm_medium=email_source=footer
>  .
> For more options, visit https://groups.google.com/d/optout.
> 

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/2038894656.742154.1522760902201%40connect.xfinity.com.
For more options, visit https://groups.google.com/d/optout.


Re: How to run an external command that must run with the server

2018-04-01 Thread Ken Whitesell
We set up all our Django-related processes as a group under supervisor. 
This includes our celery-based processes. (We have some long-running 
tasks that are kicked off by the web site.) By setting it up as a group, 
we can manage all the different processes as a set.


Whether or not that's the "best" way is possibly debatable. But it works 
for us and doesn't give us any problems.


Ken

On 4/1/2018 7:06 AM, 'Alex' via Django users wrote:
I have a daphne server running a django channels application. I also 
have a python script that aggregates data from various sources, and 
sticks it into the channel layer (called source.py). At the moment, I 
run it as a management command (python manage.py source). It is nearly 
time for deployment(!), so I'm moving towards production solutions. 
Daphne itself currently runs under supervisor.


My question is, what is the best way to run source.py? As a management 
command, also under supervisor? Using celery? In some other way? Since 
source.py feeds into the channel layer, it needs access to settings.py 
in order to identify the details of the channel layer etc.

--
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+unsubscr...@googlegroups.com 
.
To post to this group, send email to django-users@googlegroups.com 
.

Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/b3c22939-b520-4c9c-90f9-ef8cb7b8c661%40googlegroups.com 
.

For more options, visit https://groups.google.com/d/optout.



--
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/b3acf9a3-41e9-08ee-1180-80fb5bc346d0%40comcast.net.
For more options, visit https://groups.google.com/d/optout.


Re: Django 2.0.2, Channels 2.0.2 and Celery 4.1 Issue

2018-03-02 Thread Ken Whitesell
Taking a stab at this - I believe the original problem may be here:
channel_layer.group_send(
settings.CHANNEL_GROUP,
{"type": "epics.message", "text": "Hello World"},
)

Your updateData method is a synchronous method. However, 
channel_layer.group_send is an asynchronous method.

What you might try is wrapping the group_send method in the async_to_sync 
function.
See the documentation at 
http://channels.readthedocs.io/en/latest/topics/channel_layers.html#synchronous-functions

async_to_sync(channel_layer.group_send)(
settings.CHANNEL_GROUP,
{"type": "epics.message", "text": "Hello World"},
)


Your first solution to make updateData an asynchronous method might work 
with some other work involved in adding that task to the event loop - but 
that answer is beyond me at the moment.

Hope this helps,
 Ken


On Friday, March 2, 2018 at 1:36:08 PM UTC-5, G Broten wrote:
>
> Hi All:
>  I'm migrating a small application from Django 1.x/Channels 1.x to Django 
> 2.0.2 and Channels 2.0. I've run into an issue whose cause I'm trying to 
> determine. It could be due to a failure on my part to correctly implement 
> the channel_layer or it could be due to an
> incompatibility with Celery 4.1. The basics are:
> - Run a periodic Celery task
> - Use the channel_layer to perform a group_send
> - Have the consumer receive the group_send event and push a json  message 
> over the socket
>
> Show below is my simple consumer.py module:
> class mstatusMessage(AsyncJsonWebsocketConsumer):
>
> # WebSocket event handlers
>
> async def connect(self):
> """
> Called when the websocket is handshaking as part of initial 
> connection.
> """
> logging.info("### Connected ###")
> # Accept the connection
> await self.accept()
>
> # Add to the group so they get messages
> await self.channel_layer.group_add(
> settings.CHANNEL_GROUP,
> self.channel_name,
> )
>
> async def disconnect(self, code):
> """
> Called when the WebSocket closes for any reason.
> """
> # Remove them from the group
> await self.channel_layer.group_discard(
> settings.CHANNEL_GROUP,
> self.channel_name,
> )
>
> # Handlers for messages sent over the channel layer
>
> # These helper methods are named by the types we send - so epics.join 
> becomes epics_join
> async def epics_message(self, event):
> """
> Called when the Celery task queries Epics.
> """
> logging.error("### Received Msg ###")
> # Send a message down to the client
> await self.send_json(
> {
> "text": event["message"],
> },
> )
>
> The routing is simple:
> application = ProtocolTypeRouter({
> "websocket":  mstatusMessage
> })
>
> The Celery task is as follows:
> @shared_task
> def updateData(param):
>
> logger.error('# updateData #')
>
> # # Get an instance of the channel layer for
> # # inter task communications
> channel_layer = get_channel_layer()
>
> channel_layer.group_send(
> settings.CHANNEL_GROUP,
> {"type": "epics.message", "text": "Hello World"},
> )
>
> The results are promising as the websocket connect opens successfully and 
> the Celery task run as show by the debugging output given below:
> 127.0.0.1:59818 - - [02/Mar/2018:09:32:11] "GET /" 200 100639
> 127.0.0.1:59844 - - [02/Mar/2018:09:32:12] "WSCONNECTING /epics/" - -
> 2018-03-02 09:32:12,280 INFO ### Connected ###
> 127.0.0.1:59844 - - [02/Mar/2018:09:32:12] "WSCONNECT /epics/" - -
> [2018-03-02 09:32:12,312: ERROR/ForkPoolWorker-2] 
> mstatus.tasks.updateData[8d329e61-]: # updateData #
> [2018-03-02 09:32:13,310: ERROR/ForkPoolWorker-2] 
> mstatus.tasks.updateData[786f51a6-]: # updateData #
>
> BUT ... although the Celery task runs the consumer never 
> receives a message via the channel layer. This could be due to an
> implementation error or, maybe, a compatibility issue. The application 
> doesn't crash but the following warning is issued:
>
> [2018-03-02 09:32:02,105: WARNING/ForkPoolWorker-2] 
> /mstatus/mstatus/tasks.py:33: RuntimeWarning: coroutine 
> 'RedisChannelLayer.group_send' was never awaited
>   {"type": "epics.message", "text": "Hello World"},
>
> This warning appears related to the Python asyncio functionality. Under 
> the Celery task module, the channel_layer.group_send
> doesn't use the await directive as it's inclusion hangs the Celery task. 
> Changing the Celery task to:
> async def updateData(param):
>
> logger.error('# updateData #')
>
> # # Get an instance of the channel layer for
> # # inter task communications
> channel_layer = get_channel_layer()
>
> await channel_layer.group_send(
> settings.CHANNEL_GROUP,
> {"type": "epics.message", 

Re: Channels 2.0 - Exception when sending a message to client

2018-02-25 Thread Ken Whitesell
And while we're at it, I'm going to toss out another opinion.

I've found it extremely beneficial _for me_ to not try to relate channels 
2.0 to channels 1.1. I'm approaching it as if I'm learning about a 
completely separate package - working from a clean slate so-to-speak.

Ken

On Sunday, February 25, 2018 at 5:04:13 AM UTC-5, muha...@swordfish.co.za 
wrote:
>
> While I'm at it, would you mind confirming if I understand the following 
> changes in channels 2.0 correctly ?
>
> 1) Channel names are not auto-detected and must be specified when running 
> a worker
> 2) *runserver* no long starts up a worker by default, this has be done 
> manually
>
>
>>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/896fab41-d482-4111-8410-b9ff690a4546%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Channels 2.0 - Exception when sending a message to client

2018-02-25 Thread Ken Whitesell
In so far as you are talking about background worker tasks, you are correct.

But those statements do not pertain to a websocket consumer that accepts 
connections from a browser. You can run an application without ever 
creating a worker task. (Again, I'll refer you to the channels-examples app 
for such a demonstration.)

Ken


On Sunday, February 25, 2018 at 5:04:13 AM UTC-5, muha...@swordfish.co.za 
wrote:
>
> While I'm at it, would you mind confirming if I understand the following 
> changes in channels 2.0 correctly ?
>
> 1) Channel names are not auto-detected and must be specified when running 
> a worker
> 2) *runserver* no long starts up a worker by default, this has be done 
> manually
>
> On Sunday, February 25, 2018 at 2:56:45 AM UTC+2, muha...@swordfish.co.za 
> wrote:
>>
>> I'm still trying to find my way around channels 2.0, so I'm not sure if 
>> my implementation is incorrect or if this is a valid issue. I'm going to 
>> post as much info as possible in the hope that it will assist with finding 
>> the problem.
>>
>> I have a single page app which opens a JS websocket connection - with 
>> channels 1 I used to add a *session_key *to the querystring and that 
>> used to handle the authentication.
>>
>> I see this is no longer the case, so I now have a custom middleware class 
>> that sets the user object on the scope:
>>
>> from django.contrib.sessions.models import Session
>>
>> from users.models import User
>>
>>
>> class QueryAuthMiddleware:
>>
>> def __init__(self, inner):
>> # Store the ASGI application we were passed
>> self.inner = inner
>>
>> def __call__(self, scope):
>> # Look up user from query string (you should also do things like
>> # check it's a valid user ID, or if scope["user"] is already 
>> populated)
>> if scope.get("user", None) is None:
>> session_obj = 
>> Session.objects.get(session_key=scope["query_string"].decode("utf-8").split("=")[1])
>> session_decoded = session_obj.get_decoded()
>>
>> scope["user"] = 
>> User.objects.get(id=session_decoded.get("_auth_user_id"))
>>
>> # Return the inner application directly and let it run 
>> everything else
>> return self.inner(scope)
>>
>>
>>
>>
>> This is in turn added to my routing (channels.py):
>>
>> from django.conf.urls import url
>> from django.conf import settings
>> from channels.routing import ProtocolTypeRouter, URLRouter, ChannelNameRouter
>>
>> from notifications.consumer import TestWebsocketConsumer, TestConsumer
>> from notifications.middleware.query_auth_middleware import 
>> QueryAuthMiddleware
>>
>> ROOT_PATH = "" if settings.DEBUG else "/ws/"
>>
>>
>> application = ProtocolTypeRouter({
>>
>> "websocket": QueryAuthMiddleware(
>> URLRouter([
>> url(f"^{ROOT_PATH}(?P[-\w]+)/$", TestWebsocketConsumer),
>>
>> ])
>> ),
>>
>> "channel": ChannelNameRouter({
>>  "user-notifications": TestConsumer,
>> })
>>
>>
>> })
>>
>>
>>
>>
>>
>> Here's my *consumers.py*:
>>
>> from asgiref.sync import async_to_sync
>> from channels.consumer import SyncConsumer
>> from channels.generic.websocket import WebsocketConsumer
>>
>>
>> class TestWebsocketConsumer(WebsocketConsumer):
>> def websocket_connect(self, message):
>> 
>> async_to_sync(self.channel_layer.group_add)(str(self.scope["user"].id), 
>> "user-notifications")
>> self.connect()
>>
>>
>> class TestConsumer(SyncConsumer):
>> def notification_handler(self, message):
>>
>> self.send(
>> {
>>  "type": "websocket.send",
>>  "text": message["text"]
>> }
>> )
>>
>>
>>
>>
>>
>>
>> The idea of the app is that each user that logs in on the front end is 
>> able to receive messages meant only for them sent by the back end.  I have 
>> been trying to test it like this:
>>
>> >>> channel_layer = get_channel_layer()
>> >>> async_to_sync(channel_layer.send)("user-notifications", {"type": 
>> >>> "notification.handler", "text": "My Message"})
>>
>>
>>
>>
>> Here's the traceback in the *runworker* output:
>>
>> 2018-02-25 02:34:14,002 - INFO - runworker - Running worker for channels 
>> ['user-notifications']
>> ERROR:root:Exception inside application: You must implement 
>> application_send()
>>   File 
>> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/channels/consumer.py",
>>  
>> line 54, in __call__
>> await await_many_dispatch([receive, self.channel_receive], 
>> self.dispatch)
>>   File 
>> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/channels/utils.py",
>>  
>> line 48, in await_many_dispatch
>> await dispatch(result)
>>   File 
>> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/asgiref/sync.py", 
>> line 110, in __call__
>> return await asyncio.wait_for(future, timeout=None)
>>   File 
>> "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py",

Re: Channels 2.0 - Exception when sending a message to client

2018-02-25 Thread Ken Whitesell
Before I get to the guts of my answer, I'd suggest you get Andrew Godwin's 
"channels-examples" application and read it completely until you believe 
you understand everything that it's doing. 
(https://github.com/andrewgodwin/channels-examples)

Now, to the extent of my understanding, the "ChannelNameRouter" is used for 
background tasks - it's not used for connections by a websocket client- so 
the API is different than the router used for a websocket.

The applicable excerpt from the routing.py file in the channels-examples 
app (comments removed - see the full file for more details):
application = ProtocolTypeRouter({
"websocket": AuthMiddlewareStack(
URLRouter([
# URLRouter just takes standard Django path() or url() entries.
path("chat/stream/", ChatConsumer),
]),
),
"channel": ChannelNameRouter({
"mpge-timer": TimerConsumer
}),

})

What this is saying to me is that in the channels world, there are (at 
least) two fundamentally different types of objects - 
1) There are websocket consumers, which are connected to by an external 
client using a websocket connection, _and_ can send and receive messages on 
the internal channel. These are defined in the "websocket" key of the 
ProtocolTypeRouter object.
When they are created by a connection being made, they are given a "scope" 
which exists for the life of the connection. This scope include a 
system-generated channel name - but it's implicit in the API that that 
consumer uses to send & receive messages - you don't specify it when making 
calls. (Don't know if that's universally true, but it's my current 
impression.)

2) There are worker tasks, which do _not_ create or use websockets to make 
a connection to the outside world. They exist to send and receive events 
via channels. (They can also make changes to your models, so strictly 
speaking, channels aren't their only means of communication to other tasks 
or processes.)

So for your task, you'll want to define your TestWebSocketConsumer within 
the websocket key of the ProtocolTypeRouter

Keep in mind that a websocket is created as an "upgrade" of a regular HTTP 
connection - hence the requirement of a url as part of the routing. 
Effectively, the client is issuing an HTTP GET request for a url, and also 
says, "Oh, by the way, I want to upgrade this connection to be a 
websocket". (The actual protocol is a little bit more complex than that - 
but not too much.) So the server gets the GET, and needs to route it to 
something that will handle that URL and provide the upgraded protocol. That 
is handled by Daphne at the lowest layers - this definition is just 
information that Daphne uses to figure out what object gets to handle each 
url.

Hope this helps.
Ken

Disclaimer: I am not Andrew Godwin, I do not play him on TV, and my code 
will never be mistaken for his. In any situation where there's a 
discrepancy between anything he has written and my comments, I am wrong. At 
this point I'm guessing I'm just about a step and a half ahead of you in 
working my way though this.


On Sunday, February 25, 2018 at 4:42:27 AM UTC-5, muha...@swordfish.co.za 
wrote:
>
> Thanks for the update - I think I understand now.
>
> I updated my channel name routing and pointed it at the Websocket consumer:
>
> "channel": ChannelNameRouter({
> "user-notifications": TestWebsocketConsumer,
> })
>
>
>
> Moved the message handler into *TestWebsocketConsumer:*
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> *from asgiref.sync import async_to_syncfrom channels.generic.websocket 
> import WebsocketConsumerclass TestWebsocketConsumer(WebsocketConsumer):
> def websocket_connect(self, message):
> async_to_sync(self.channel_layer.group_add)(str(self.scope["user"].id), 
> "user-notifications")self.connect()def 
> notification_handler(self, message):self.send({
>  "text": message["text"]})*
> This raises the same exception:
>
> ERROR:root:Exception inside application: You must implement 
> application_send()
>   File 
> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/channels/consumer.py",
>  
> line 54, in __call__
> await await_many_dispatch([receive, self.channel_receive], 
> self.dispatch)
>   File 
> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/channels/utils.py", 
> line 48, in await_many_dispatch
> await dispatch(result)
>   File 
> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/asgiref/sync.py", 
> line 110, in __call__
> return await asyncio.wait_for(future, timeout=None)
>   File 
> "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/tasks.py",
>  
> line 333, in wait_for
> return (yield from fut)
>   File 
> "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/concurrent/futures/thread.py",
>  
> line 55, in run
> result = self.fn(*self.args, 

Re: Simple Search Feature

2018-02-24 Thread Ken Whitesell
One of the issues is here:
if request.method == 'GET':
song_name = request.GET.get('name', "Error")
songs = self.model.objects.filter(name__icontains=song_name)
else:
songs = self.models.all()
return render(request, self.template_name, {'songs': songs})

When no parameter is passed, request.method is still "GET" - In fact, this 
method should only be called on a get method, making this test irrelevant.

You _could_ change it to look something like this:
song_name = request.GET.get('name', None)
if song_name:
songs = self.model.objects.filter(name__icontains=song_name)
else:
songs = self.models.all()
return render(request, self.template_name, {'songs': songs})

Hope this helps,
 Ken


On Saturday, February 24, 2018 at 8:18:25 PM UTC-5, tangoward15 wrote:
>
> Hi,
>
> I am playing around on adding a search feature to a website. I am 
> currently encountering a problem when the page should load a list of songs 
> and after typing in a song title in the search box:
>
>
> views.py
>
> class SongListView(ListView):
> model = SongOne 
> context_object_name = 'songs'
> template_name = 'songs/song_list.html'
>
> def get(self, request, *args, **kwargs):
>
> if request.method == 'GET':
> song_name = request.GET.get('name', "Error")
> songs = self.model.objects.filter(name__icontains=song_name)
> else:
> songs = self.models.all()
> return render(request, self.template_name, {'songs': songs})
>
> problem is when I click the search button with the text box empty, I am 
> getting the list of all the song (url: /songs/?name=) but if I just load 
> the page wihout clicking the submit button (url: /songs/), it doesn't give 
> me the list all the songs. The search box works if I type the correct song 
> name as it shows the song title.  Problem is the page should load all the 
> songs before I search a particular song.
>
> Any suggestions so I can enhance my code?
>
>
> Thanks,
> Jarvis
>
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/fee7baf6-7dbe-4a33-a281-f7c8600f73cc%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Channels 2.0 - Exception when sending a message to client

2018-02-24 Thread Ken Whitesell
I'm going to take a stab at this - with the warning that I'm extremely 
uncertain that I'm anywhere close to being correct, but I'm hoping that I'm 
at least close enough that it might give you some clues.

So where I think the issue may be is that you're trying to do a "self.send" 
from a worker task, not from a websocket task. If you look at the docs for 
the "Worker and Background Tasks", you'll see that to send an event you 
call "self.channel_layer.send" with a first parameter of the channel to 
which you wish to send the message.

Since this worker task isn't running in the context of a websocket 
consumer, it doesn't automatically know to which channel a response should 
be sent. (I _know_ that my wording there is imprecise and probably 
inaccurate, but I think I'm sufficiently close for casual conversation.)

If you want the worker task to send a message back to a client, what _I_ 
have done is create another method in my WebSocket consumer that takes a 
message and forwards it back out to the client. In thinking about it, I 
guess it may be possible that if I pass something (whatever that 
"something" might be) to the worker task, I might be able to send a message 
back out without going back through the consumer - again, that's a guess 
for something I haven't tried yet.

Anyway, I hope this helps.

Ken

On Saturday, February 24, 2018 at 7:56:45 PM UTC-5, muha...@swordfish.co.za 
wrote:
>
> I'm still trying to find my way around channels 2.0, so I'm not sure if my 
> implementation is incorrect or if this is a valid issue. I'm going to post 
> as much info as possible in the hope that it will assist with finding the 
> problem.
>
> I have a single page app which opens a JS websocket connection - with 
> channels 1 I used to add a *session_key *to the querystring and that used 
> to handle the authentication.
>
> I see this is no longer the case, so I now have a custom middleware class 
> that sets the user object on the scope:
>
> from django.contrib.sessions.models import Session
>
> from users.models import User
>
>
> class QueryAuthMiddleware:
>
> def __init__(self, inner):
> # Store the ASGI application we were passed
> self.inner = inner
>
> def __call__(self, scope):
> # Look up user from query string (you should also do things like
> # check it's a valid user ID, or if scope["user"] is already 
> populated)
> if scope.get("user", None) is None:
> session_obj = 
> Session.objects.get(session_key=scope["query_string"].decode("utf-8").split("=")[1])
> session_decoded = session_obj.get_decoded()
>
> scope["user"] = 
> User.objects.get(id=session_decoded.get("_auth_user_id"))
>
> # Return the inner application directly and let it run everything 
> else
> return self.inner(scope)
>
>
>
>
> This is in turn added to my routing (channels.py):
>
> from django.conf.urls import url
> from django.conf import settings
> from channels.routing import ProtocolTypeRouter, URLRouter, ChannelNameRouter
>
> from notifications.consumer import TestWebsocketConsumer, TestConsumer
> from notifications.middleware.query_auth_middleware import QueryAuthMiddleware
>
> ROOT_PATH = "" if settings.DEBUG else "/ws/"
>
>
> application = ProtocolTypeRouter({
>
> "websocket": QueryAuthMiddleware(
> URLRouter([
> url(f"^{ROOT_PATH}(?P[-\w]+)/$", TestWebsocketConsumer),
>
> ])
> ),
>
> "channel": ChannelNameRouter({
>  "user-notifications": TestConsumer,
> })
>
>
> })
>
>
>
>
>
> Here's my *consumers.py*:
>
> from asgiref.sync import async_to_sync
> from channels.consumer import SyncConsumer
> from channels.generic.websocket import WebsocketConsumer
>
>
> class TestWebsocketConsumer(WebsocketConsumer):
> def websocket_connect(self, message):
> 
> async_to_sync(self.channel_layer.group_add)(str(self.scope["user"].id), 
> "user-notifications")
> self.connect()
>
>
> class TestConsumer(SyncConsumer):
> def notification_handler(self, message):
>
> self.send(
> {
>  "type": "websocket.send",
>  "text": message["text"]
> }
> )
>
>
>
>
>
>
> The idea of the app is that each user that logs in on the front end is 
> able to receive messages meant only for them sent by the back end.  I have 
> been trying to test it like this:
>
> >>> channel_layer = get_channel_layer()
> >>> async_to_sync(channel_layer.send)("user-notifications", {"type": 
> >>> "notification.handler", "text": "My Message"})
>
>
>
>
> Here's the traceback in the *runworker* output:
>
> 2018-02-25 02:34:14,002 - INFO - runworker - Running worker for channels 
> ['user-notifications']
> ERROR:root:Exception inside application: You must implement 
> application_send()
>   File 
> "/Users/muhammed/projects/xxx/lib/python3.6/site-packages/channels/consumer.py",
>  
> line 54, in __call__
> await await_many_dispatch([receive, 

Re: Channels worker and call_later

2018-02-23 Thread Ken Whitesell
Andrew,

 Thanks for the quick reply! Yea, I kinda guessed I was overthinking 
this. Your solution works 100% for exactly what I'm trying to do.

Sorry about the confusion regarding my reference to Twisted, it's no part 
of this particular project - I only mentioned it to state that while it has 
been awhile, I do have some familiarity with (in a general sense) 
asynchronous / event-driven programming in Python, but no specific 
knowledge of the current asyncio in Python 3.6 - so while I'm comfortable 
with the general concepts, there are a lot of the specifics that I'm still 
picking up.

Anyway, thanks again!

Ken 


On Friday, February 23, 2018 at 10:56:03 PM UTC-5, Andrew Godwin wrote:
>
> Hi Ken,
>
> You should write asyncio code, rather than Twisted code - we have Twisted 
> running on it asyncio reactor so both are available, and asyncio is the 
> only thing you're guaranteed from the spec/other future servers.
>
> Given that, I would recommend making a separate asyncio Task that has an 
> "await asyncio.sleep(30)" in it and then does what you want. If you then 
> need to cancel the task, you can call ".cancel()" on it (and remember, you 
> can put it on `self` if you need to keep a reference).
>
> To make a task, just do:
>
> loop = asyncio.get_event_loop()
> self.task = loop.create_task(coroutine_function())
>
> Hope that helps!
>
> Andrew
>
> On Fri, Feb 23, 2018 at 7:48 PM, Ken Whitesell <kenwhi...@comcast.net 
> > wrote:
>
>> TLDR: Is there a way to use the call_later function within a worker task? 
>> (Or am I just looking at this issue the wrong way?)
>>
>> Software - Python 3.6, Django 2.0.2, Channels 2.0.2, trying to run this 
>> on either / both Windows 10 and Ubuntu 17.10 if it matters
>>
>> Longer version - I'm having surprisingly few problems with wrapping my 
>> head around the new Channels 2, especially since this is the first I've 
>> been using asyncio and it's been about 10 years since I've used Twisted. 
>> All my personal sample code that I've been trying to write has been working 
>> great.
>>
>> Except... I have the situation where I want to schedule an event for some 
>> fixed period of time in the future - say 30 seconds.
>> But, it's also necessary for me to be able to cancel that scheduled event.
>>
>> I've tried a number of different combinations for the worker task between 
>> SyncConsumer and AsyncConsumer, and different combinations of async and 
>> regular methods, and get a variety of different errors. But the bottom line 
>> is that I haven't stumbled across the magic sauce that will let this work.
>>
>> I _can_ get the delay to work by using the asyncio.sleep method, using 
>> the pattern shown in the "Delay server" paragraph in the "What's new in 
>> Channels 2?" section of the docs. But while that method (sleep) returns a 
>> generator object, I don't see where that does me any good with trying to 
>> cancel that sleep.
>>
>> I know I can make this work by setting some variable, and check that 
>> after the sleep has finished to determine whether or not I still need to do 
>> my work, but that just "feels wrong" to me for some reason.
>>
>> Is there something simple that I'm missing? Or does this fit into the 
>> category of "Don't do that!"
>>
>> Thanks,
>>  Ken
>>
>> -- 
>> 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...@googlegroups.com .
>> To post to this group, send email to django...@googlegroups.com 
>> .
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-users/642da2f0-5c07-44ee-9059-a366ef67de14%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/django-users/642da2f0-5c07-44ee-9059-a366ef67de14%40googlegroups.com?utm_medium=email_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/ae18c2ea-5503-4c97-85e1-121c5a765ae2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Channels worker and call_later

2018-02-23 Thread Ken Whitesell
TLDR: Is there a way to use the call_later function within a worker task? 
(Or am I just looking at this issue the wrong way?)

Software - Python 3.6, Django 2.0.2, Channels 2.0.2, trying to run this on 
either / both Windows 10 and Ubuntu 17.10 if it matters

Longer version - I'm having surprisingly few problems with wrapping my head 
around the new Channels 2, especially since this is the first I've been 
using asyncio and it's been about 10 years since I've used Twisted. All my 
personal sample code that I've been trying to write has been working great.

Except... I have the situation where I want to schedule an event for some 
fixed period of time in the future - say 30 seconds.
But, it's also necessary for me to be able to cancel that scheduled event.

I've tried a number of different combinations for the worker task between 
SyncConsumer and AsyncConsumer, and different combinations of async and 
regular methods, and get a variety of different errors. But the bottom line 
is that I haven't stumbled across the magic sauce that will let this work.

I _can_ get the delay to work by using the asyncio.sleep method, using the 
pattern shown in the "Delay server" paragraph in the "What's new in 
Channels 2?" section of the docs. But while that method (sleep) returns a 
generator object, I don't see where that does me any good with trying to 
cancel that sleep.

I know I can make this work by setting some variable, and check that after 
the sleep has finished to determine whether or not I still need to do my 
work, but that just "feels wrong" to me for some reason.

Is there something simple that I'm missing? Or does this fit into the 
category of "Don't do that!"

Thanks,
 Ken

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/642da2f0-5c07-44ee-9059-a366ef67de14%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.