Re: Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread Ryan Hiebert
I would also love to see a decent way to use enums as choices. The
translation issues seem the stickiest to me, but I'm kinda hoping we can
come up with something reasonable.

I'm a heavy user, but mostly a lurker on this list, but +1 from me for what
it's worth.

Ryan

On Mon, Dec 31, 2018, 17:41 Tom Forbes  Unfortunately I made this for a python 2 app before enums where in the
> standard library. I think it has some useful ideas though especially around
> categories, which I find I needed a lot. I'd be interested to know if
> anyone else has written any workflow-driven apps in Django that require
> groups of choice values (i.e "if value in Choices.SOME_GROUP)?
>
> Its a shame about the way xgetext worked, but I guess it's not too bad to
> duplicate this if you require it. I'm not too familiar with it and assumed
> it worked by importing modules and recording calls to the function.
>
> In any case, we could make the display text optional if you do not require
> translations and generate them from the keys?
>
> The way Django handles choices has always irked me as it's really not DRY,
> you need to create sort-of enums using class or global variables and
> tuples. It's repetitive and boring, and honestly enums made this much more
> usable.
>
> We currently have a -1 and a +1, does anyone else have any input on this?
>
> Tom
>
> On Mon, 31 Dec 2018, 22:15 Shai Berger 
>> Hi Tom,
>>
>> On Mon, 31 Dec 2018 18:26:14 +
>> Tom Forbes  wrote:
>>
>> > I was describing my django-choice-object library[1] and forgot to
>> > link it!
>> >
>>
>> Thanks, I took a look -- the library looks nice, but notably, Choice
>> objects are not Python enums, although they share some of their traits.
>>
>> > I would be +1 on re-opening it, I've used enums for this before and I
>> > find it much more DRY than the more 'standard' Django way.
>>
>> Thanks.
>>
>> > Perhaps we could reduce some boilerplate here by somehow automatically
>> adding
>> > the key names to gettext?
>> >
>>
>> This, I'm afraid, won't fly. The way xgettext (the engine used by
>> makemessages) generates the translation files is by scanning the text
>> of source files, looking for specific function calls, and picking their
>> arguments with a simple text transformation. So, for the key name to
>> somehow be identified, it must be a parameter in a function call (not
>> the target of assignment), and the form to be translated must be the
>> form that's in the source -- no changing capitalization, or
>> underscores-to-spaces, or anything of the sort. So, the best we could
>> do to minimize repetitions would create Choice classes looking like
>>
>> class SchoolYear(Choices):
>> choice('Freshman', 'FR')
>> choice('Junior', 'JR')
>>
>> where the choice() calls add members to the class, and the name of the
>> member is generated by some transformation over the label. That,
>> IMO, would be unacceptably unpythonic.
>>
>> Have fun,
>> Shai.
>>
>> > 1. https://github.com/orf/django-choice-object
>> >
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Django developers  (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to django-developers+unsubscr...@googlegroups.com.
>> To post to this group, send email to django-developers@googlegroups.com.
>> Visit this group at https://groups.google.com/group/django-developers.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/django-developers/20190101001534.29c8c673.shai%40platonix.com
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/CAFNZOJPJcqi7bELk_1QFOp3ZMZV1njYd9nWSc_bumymkzta1BQ%40mail.gmail.com
> 
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 

Re: Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread Tom Forbes
Unfortunately I made this for a python 2 app before enums where in the
standard library. I think it has some useful ideas though especially around
categories, which I find I needed a lot. I'd be interested to know if
anyone else has written any workflow-driven apps in Django that require
groups of choice values (i.e "if value in Choices.SOME_GROUP)?

Its a shame about the way xgetext worked, but I guess it's not too bad to
duplicate this if you require it. I'm not too familiar with it and assumed
it worked by importing modules and recording calls to the function.

In any case, we could make the display text optional if you do not require
translations and generate them from the keys?

The way Django handles choices has always irked me as it's really not DRY,
you need to create sort-of enums using class or global variables and
tuples. It's repetitive and boring, and honestly enums made this much more
usable.

We currently have a -1 and a +1, does anyone else have any input on this?

Tom

On Mon, 31 Dec 2018, 22:15 Shai Berger  Hi Tom,
>
> On Mon, 31 Dec 2018 18:26:14 +
> Tom Forbes  wrote:
>
> > I was describing my django-choice-object library[1] and forgot to
> > link it!
> >
>
> Thanks, I took a look -- the library looks nice, but notably, Choice
> objects are not Python enums, although they share some of their traits.
>
> > I would be +1 on re-opening it, I've used enums for this before and I
> > find it much more DRY than the more 'standard' Django way.
>
> Thanks.
>
> > Perhaps we could reduce some boilerplate here by somehow automatically
> adding
> > the key names to gettext?
> >
>
> This, I'm afraid, won't fly. The way xgettext (the engine used by
> makemessages) generates the translation files is by scanning the text
> of source files, looking for specific function calls, and picking their
> arguments with a simple text transformation. So, for the key name to
> somehow be identified, it must be a parameter in a function call (not
> the target of assignment), and the form to be translated must be the
> form that's in the source -- no changing capitalization, or
> underscores-to-spaces, or anything of the sort. So, the best we could
> do to minimize repetitions would create Choice classes looking like
>
> class SchoolYear(Choices):
> choice('Freshman', 'FR')
> choice('Junior', 'JR')
>
> where the choice() calls add members to the class, and the name of the
> member is generated by some transformation over the label. That,
> IMO, would be unacceptably unpythonic.
>
> Have fun,
> Shai.
>
> > 1. https://github.com/orf/django-choice-object
> >
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers  (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/20190101001534.29c8c673.shai%40platonix.com
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/CAFNZOJPJcqi7bELk_1QFOp3ZMZV1njYd9nWSc_bumymkzta1BQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread Shai Berger
Hi Tom,

On Mon, 31 Dec 2018 18:26:14 +
Tom Forbes  wrote:

> I was describing my django-choice-object library[1] and forgot to
> link it!
> 

Thanks, I took a look -- the library looks nice, but notably, Choice
objects are not Python enums, although they share some of their traits.

> I would be +1 on re-opening it, I've used enums for this before and I
> find it much more DRY than the more 'standard' Django way.

Thanks.

> Perhaps we could reduce some boilerplate here by somehow automatically adding
> the key names to gettext?
> 

This, I'm afraid, won't fly. The way xgettext (the engine used by
makemessages) generates the translation files is by scanning the text
of source files, looking for specific function calls, and picking their
arguments with a simple text transformation. So, for the key name to
somehow be identified, it must be a parameter in a function call (not
the target of assignment), and the form to be translated must be the
form that's in the source -- no changing capitalization, or
underscores-to-spaces, or anything of the sort. So, the best we could
do to minimize repetitions would create Choice classes looking like

class SchoolYear(Choices):
choice('Freshman', 'FR')
choice('Junior', 'JR')

where the choice() calls add members to the class, and the name of the
member is generated by some transformation over the label. That,
IMO, would be unacceptably unpythonic.

Have fun,
Shai.

> 1. https://github.com/orf/django-choice-object
> 

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/20190101001534.29c8c673.shai%40platonix.com.
For more options, visit https://groups.google.com/d/optout.


Re: Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread Shai Berger
Hi James,

On Mon, 31 Dec 2018 10:24:39 -0800
James Bennett  wrote:

> The basic problem is that, to take the example in the ticket, if I
> were to issue a request like "/students/?year=FR", and the view were
> to read that "year" param and try to filter on it, it would fail --
> the string "FR" will not compare equal to the enum member "FR". So I
> couldn't easily use that to filter for students whose year is
> Student.YearInSchool.Freshman.

Like so:

>>> class SchoolYear(Enum):
...   FRESHMAN = 'FR'
...   JUNIOR   = 'JR'
... 
>>> SchoolYear.FRESHMAN == 'FR'
False

>
> 
> This is a deliberate design decision in Python's enums which,
> unfortunately, makes them unsuitable for the kinds of things people
> would commonly use them for in Django; only the special one-off
> enum.IntEnum has members that actually are comparable to a base
> Python type, and writing special-case enum variants for other types
> to try to enable comparability would be a pain.
> 

The actual definition of IntEnum is

class IntEnum(int, Enum):
"""Enum where members are also (and must be) ints"""

(it turns out that you don't need a 'pass' statement when you have a
docstring). And indeed,

>>> class SchoolYear(str, Enum):
...   FRESHMAN = 'FR'
...   JUNIOR   = 'JR'
... 
>>> SchoolYear.FRESHMAN == 'FR'
True

All it takes is adding the base Python type as a base of your
enumeration type.

Shai.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/20181231231946.1d973327.shai%40platonix.com.
For more options, visit https://groups.google.com/d/optout.


Re: Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread Tom Forbes
Hey Shai,
I have not had a chance to look at the implementation, but I was describing
my django-choice-object library[1] and forgot to link it!

I would be +1 on re-opening it, I've used enums for this before and I find
it much more DRY than the more 'standard' Django way. Perhaps we could
reduce some boilerplate here by somehow automatically adding the key names
to gettext?

1. https://github.com/orf/django-choice-object

On Mon, 31 Dec 2018, 18:19 Shai Berger  Hi all,
>
> Lately I've run into ticket 27910[1], which asks for Python Enums to be
> usable for generating choices in Django model (and form) fields. This
> ticket was closed Wontfix because the original suggestion did not offer
> any way to handle translated labels. However, after the ticket was
> closed, Tom Forbes brought up a suggestion for a suitable API;
> regretfully, AFAICT this suggestion was never discussed here, and (at
> least on the ticket) Tom hasn't shared his implementation.
>
> Inspired by his description, I came up with an implementation[2] that is
> simple -- less than 20 lines of executable code -- and I think has a
> lot of nice properties. I think this can make choices-related code
> significantly more elegant.
>
> May we please reopen the ticket?
>
> Thanks,
> Shai.
>
> [1] https://code.djangoproject.com/ticket/27910
> [2]
> https://github.com/django/django/compare/master...shaib:ticket_27910?expand=1
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers  (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/20181231201915.6709633b.shai%40platonix.com
> .
> For more options, visit https://groups.google.com/d/optout.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/CAFNZOJMie_bAtpFHti2Qk59P0kU2LF4ENLtfvFd%2BiZGuQHDNVg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Re: Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread James Bennett
FWIW I'm pretty strongly -1 on this feature because Python's enums don't
behave the way people want them to for many use cases.

The basic problem is that, to take the example in the ticket, if I were to
issue a request like "/students/?year=FR", and the view were to read that
"year" param and try to filter on it, it would fail -- the string "FR" will
not compare equal to the enum member "FR". So I couldn't easily use that to
filter for students whose year is Student.YearInSchool.Freshman.

This is a deliberate design decision in Python's enums which,
unfortunately, makes them unsuitable for the kinds of things people would
commonly use them for in Django; only the special one-off enum.IntEnum has
members that actually are comparable to a base Python type, and writing
special-case enum variants for other types to try to enable comparability
would be a pain.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/CAL13Cg8sn4FdjmFmsKenx_MTWNPC2TuE4vhEWpsM%2B%3DGReW4OwQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


Request to reconsider ticket #27910: using an Enum class in model Field choices

2018-12-31 Thread Shai Berger
Hi all,

Lately I've run into ticket 27910[1], which asks for Python Enums to be
usable for generating choices in Django model (and form) fields. This
ticket was closed Wontfix because the original suggestion did not offer
any way to handle translated labels. However, after the ticket was
closed, Tom Forbes brought up a suggestion for a suitable API;
regretfully, AFAICT this suggestion was never discussed here, and (at
least on the ticket) Tom hasn't shared his implementation.

Inspired by his description, I came up with an implementation[2] that is
simple -- less than 20 lines of executable code -- and I think has a
lot of nice properties. I think this can make choices-related code
significantly more elegant.

May we please reopen the ticket?

Thanks,
Shai.

[1] https://code.djangoproject.com/ticket/27910
[2]https://github.com/django/django/compare/master...shaib:ticket_27910?expand=1

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/20181231201915.6709633b.shai%40platonix.com.
For more options, visit https://groups.google.com/d/optout.


Re: RFC: #30053 Allow for conditional QuerySet.update_or_create()

2018-12-31 Thread Joshua Cannon
Personally, the snippet suggested in the ticket is sufficient for my needs 
(although I'm saddened by having to duplicate the setattr logic).
However, I filed the ticket after Googling "Django conditional 
update_or_create" and finding no appropriate solution. You might be right 
about the use case being niche, however others have ran into this too, with 
the proposed solutions being less-than-ideal.
(I won't link anything here, but searching stackoverflow for "Django 
conditional update_or_create" should lead you to the same question/answers 
I came across).

Perhaps the "solution" here isn't additional code, but rather a section in 
documentation that suggests a solution? It's extremely unfortunate that 
this is easy to get wrong in so many ways, but also isn't appropriate to 
add directly to Django.



On Friday, December 28, 2018 at 12:38:04 PM UTC-6, Adam Johnson wrote:
>
> I think the use case is probably quite niche, and I'd like to know some 
> more concrete details than the current comment on the ticket "(E.g. only 
> update if the value of a DateTimeField is less than some value)". It may be 
> there's a way to achieve the same application-level outcome using a 
> different design. If it is necessary, there are also some analogous use 
> cases, like passing a 'create' condition predicate or passing conditions to 
> get_or_create, that it seems it would make sense to implement at the same 
> time but would complicate Django and the scope of the change further.
>
> Also I agree with Simon that passing around predicate callables doesn't 
> feel very Django-ey or pythonic.
>
> On Fri, 28 Dec 2018 at 16:31, charettes > 
> wrote:
>
>> Thanks for taking the time to post here Joshua!
>>
>> The main reason why I asked to gather feedback from this list is that I'm 
>> not convinced
>> that the benefits outweighs the additional complexity this will add to 
>> the already quite
>> loaded update_or_create() signature handling and how the fact a callable 
>> predicate
>> is not something that is used anywhere else in Django AFAIK.
>>
>> The fact this can be achieved with the same number of queries by doing a
>> save(update_fields) from the return value of a previous get_or_create 
>> with a
>> bit of boilerplate[0] pushes me to a -1 because I don't think it's a 
>> common enough
>> pattern to warrant the addition of a specialized option.
>>
>> Cheers,
>> Simon
>>
>> [0] https://code.djangoproject.com/ticket/30053#comment:13
>>
>> Le vendredi 28 décembre 2018 11:15:33 UTC-5, Joshua Cannon a écrit :
>>>
>>> Howdy folks!
>>>
>>> At the suggestion of Simon Charette, I'd like to get feedback on how the 
>>> community feels about the feature request #30053 
>>> .
>>> The gist of the problem is that sometimes the "update" part of 
>>> "update_or_create" should be conditional. The proposed solution adds a 
>>> backwards-compatible "update_condition" parameter to "update_or_create" 
>>> which should be a unary callable that takes in the retrieved table instance 
>>> and returns a boolean of whether the update should be performed.
>>>
>>> Nasir Hussain has already started work on a possible solution on PR 
>>> 10800 .
>>>
>>> I'd love to hear other people's thoughts.
>>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Django developers (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to django-develop...@googlegroups.com .
>> To post to this group, send email to django-d...@googlegroups.com 
>> .
>> Visit this group at https://groups.google.com/group/django-developers.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-developers/82df287a-9e59-496b-956e-b0d4bd79760d%40googlegroups.com
>>  
>> 
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
> -- 
> Adam
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/14f8cae0-0df1-4974-b80f-41e689e0d0d8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Listening for postgres NOTIFY with django.db - adding support for connection.fileno()

2018-12-31 Thread Fábio Molinar
Hi, 

I have a custom method on my model manager that allows me to listen for 
notifications from modifications on the DB using postgreSQL. A short 
version of this code looks like this:

def listen_for_notify(self):
import select
import psycopg2
import psycopg2.extensions

from django.conf import settings

db_data = settings.DATABASES['default']
listened = None
returned_empty = None
search_timeout = 15

conn = psycopg2.connect(dbname=db_data['NAME'], 
user=db_data['USER'], password=db_data['PASSWORD'], host=db_data['HOST'], 
port=db_data['PORT'])

conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
curs = conn.cursor()
curs.execute("LISTEN default;") 

timeout = timezone.now() + timezone.timedelta(0, search_timeout)
while timezone.now() < timeout:
time_diff = timeout - timezone.now()
if select.select([conn], [], [], float(time_diff.seconds)) == 
([], [], []):
listened = False
timeout = timezone.now()
else:
conn.poll()
while conn.notifies:
notify = conn.notifies.pop(0)
if notify.payload == "notified":
listened = True
returned_empty = False
timeout = timezone.now()
if notify.payload == 'search request returned empty':
listened = True
returned_empty = True
timeout = timezone.now()
curs.close()
conn.close()
return listened, returned_empty

It would be really nice if instead of using the psycopg2 library, I could 
use only django.db. Something like this:

def listen_for_notify(self):
from django.db import connection as conn

listened = None
returned_empty = None
search_timeout = 15

with conn.cursor() as curs
timeout = timezone.now() + timezone.timedelta(0, search_timeout)
while timezone.now() < timeout:
time_diff = timeout - timezone.now()
if select.select([conn], [], [], float(time_diff.seconds)) == ([], [], []):
listened = False
timeout = timezone.now()
else:
conn.poll()
while conn.notifies:
notify = conn.notifies.pop(0)
if notify.payload == "notified":
listened = True
returned_empty = False
timeout = timezone.now()
if notify.payload == 'search request returned empty':
listened = True
returned_empty = True
timeout = timezone.now()
return listened, returned_empty

I tried out the solution above using django.db, but it doesn't work because 
the django.db.connection object don't have a fileno() method.

Is this currently not supported or am I missing something? I though that 
the django.db is kind of just a wrapper around the actual psycopg2 library. 
So I wonder why I can't use the fileno() method on it.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/b25d7b65-57d2-4547-9f3e-8ebfcb3641e6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.