Re: [Django] #30564: Cannot create custom field that returns a queryset AND uses pre_save().

2019-06-13 Thread Django
#30564: Cannot create custom field that returns a queryset AND uses pre_save().
-+-
 Reporter:  Dan J Strohl |Owner:  nobody
 Type:  Bug  |   Status:  closed
Component:  Database layer   |  Version:  master
  (models, ORM)  |
 Severity:  Normal   |   Resolution:  invalid
 Keywords:   | Triage Stage:
 |  Unreviewed
Has patch:  0|  Needs documentation:  0
  Needs tests:  0|  Patch needs improvement:  0
Easy pickings:  0|UI/UX:  0
-+-
Changes (by felixxm):

 * status:  new => closed
 * resolution:   => invalid


Comment:

 > Either way though, the bug I am reporting is that when returning a
 django queryset, via a custom field with a pre_save, it raises an
 AttributeError. Since these are all normal Django objects, and I'm using
 documented django approaches, I see this as a bug.

 Your custom field implementation is quite complicated. Custom fields with
 `pre_save()` works properly because you can treat any Django's field as a
 custom field e.g. `DateField`. It seems (but it is hard to tell without
 `pre_save_func()`) that in your case `pre_save()` returns `Query` which is
 not expected by `SQLInsertCompiler.prepare_value()`, that's why IMO it is
 an issue in your implementation/approach.

 > Since these are all normal Django objects.

 You cannot assume that Django internals will handle everything, even if
 these objects are defined by Django.

 I think that `return self.get_db_prep_value(value)` in `pre_save()` in
 branch with `pre_save_func()` should fix your issue.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.70da6bf7f642a2f576a11e5a07c225f0%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.


Re: [Django] #30564: Cannot create custom field that returns a queryset AND uses pre_save().

2019-06-13 Thread Django
#30564: Cannot create custom field that returns a queryset AND uses pre_save().
-+-
 Reporter:  Dan J Strohl |Owner:  nobody
 Type:  Bug  |   Status:  new
Component:  Database layer   |  Version:  master
  (models, ORM)  |
 Severity:  Normal   |   Resolution:
 Keywords:   | Triage Stage:
 |  Unreviewed
Has patch:  0|  Needs documentation:  0
  Needs tests:  0|  Patch needs improvement:  0
Easy pickings:  0|UI/UX:  0
-+-

Comment (by Simon Charette):

 > The issue is that by using if hasattr(value, 'resolve_expression'), you
 cannot deterministically tell the difference between a SQL expression and
 a Django QuerySet.

 FWIW even if the `QuerySet` class doesn't completely implement the
 expression API it partially behaves like one; that's what makes usage of
 `QuerySet` as subqueries work (e.g.
 `.filter(foo__in=Foo.objects.filter(bar=1))`. In that sense `QuerySet` is
 an SQL expression.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.b3824253d8ba3376bdbae24266f47479%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.


Re: [Django] #30564: Cannot create custom field that returns a queryset AND uses pre_save().

2019-06-13 Thread Django
#30564: Cannot create custom field that returns a queryset AND uses pre_save().
-+-
 Reporter:  Dan J Strohl |Owner:  nobody
 Type:  Bug  |   Status:  new
Component:  Database layer   |  Version:  master
  (models, ORM)  |
 Severity:  Normal   |   Resolution:
 Keywords:   | Triage Stage:
 |  Unreviewed
Has patch:  0|  Needs documentation:  0
  Needs tests:  0|  Patch needs improvement:  0
Easy pickings:  0|UI/UX:  0
-+-
Changes (by Dan J Strohl):

 * status:  closed => new
 * resolution:  invalid =>


Comment:

 Re-opening this, I think you mis-understood my point.  I understand that
 there are other approaches I can take, and I am looking at them  (and am
 happy for the suggestions).  however, the issue as I reported it actually
 IS with Django.  The issue is that by using ```if hasattr(value,
 'resolve_expression')```, you cannot deterministically tell the difference
 between a SQL expression and a Django QuerySet.  perhaps there is a way
 around this that I haven't seen, in which case, I apologize for missing
 it.  however by following the docs, when I return a QuerySet object, and
 when a pre_save method is used, the system raises an error since the
 QuerySet object matches your check, but is not an expression object. (or,
 if you ARE considering it an expression object for some reason, then the
 bug is that it does not have all of the OTHER required methods that the
 expected one does.).

 I understand that using ```if hasattr``` is the preferred approach, and I
 am not saying that the only fix is to change that, you could so a second
 check after it, change the method name in the queryset, have an
 alternative path that doesn't check for the method... etc... (all of which
 seem like much more work than changing the "if" check), but there may be
 other issues that I don't see (I haven't looked deeply enough at the code
 to see what other issues that would cause).  I don't know the flow or code
 well enough to say either way.  I simply brought it up as a potential
 approach.

 Either way though, the bug I am reporting is that when returning a django
 queryset, via a custom field with a pre_save, it raises an AttributeError.
 Since these are all normal Django objects, and I'm using documented django
 approaches, I see this as a bug.  If the returned object was something I
 controlled, I would simply re-name the "resolve_expression" method so it
 didn't' get caught, but I can't (easily) do that for a django QuerySet.

 I won't argue this again if you want to close this again, I'm not trying
 to get into a war here or anything.  I think it's pretty much a corner
 case, but I do see it as a bug and wanted to make sure I was at least
 being clear.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.28ecb6df664bafddd923c2355744883d%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.


Re: [Django] #30564: Cannot create custom field that returns a queryset AND uses pre_save(). (was: Cannot create custom field that returns a queryset AND uses pre_save())

2019-06-12 Thread Django
#30564: Cannot create custom field that returns a queryset AND uses pre_save().
-+-
 Reporter:  Dan J Strohl |Owner:  nobody
 Type:  Bug  |   Status:  closed
Component:  Database layer   |  Version:  master
  (models, ORM)  |
 Severity:  Normal   |   Resolution:  invalid
 Keywords:   | Triage Stage:
 |  Unreviewed
Has patch:  0|  Needs documentation:  0
  Needs tests:  0|  Patch needs improvement:  0
Easy pickings:  0|UI/UX:  0
-+-
Changes (by felixxm):

 * status:  new => closed
 * version:  2.2 => master
 * resolution:   => invalid


Comment:

 Thanks for the report, however it is not an issue in Django. It seems that
 you want to get help with your custom implementation.

 If you're on PostgreSQL you can use
 [https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/#arrayfield
 ArrayField] without implementing a custom field. If you're on a different
 database and you need to implement a custom field for that, then please
 use one of
 [https://code.djangoproject.com/wiki/TicketClosingReasons/UseSupportChannels
 support channels].

 `if hasattr(value, 'resolve_expression')` is the way that we prefer to
 check if something is an expression, it is used in many places.


 Closing per TicketClosingReasons/UseSupportChannels.

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.a95e4555d5060c92989336cd3b6c4d11%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.


Re: [Django] #30564: Cannot create custom field that returns a queryset AND uses pre_save()

2019-06-12 Thread Django
#30564: Cannot create custom field that returns a queryset AND uses pre_save()
-+-
 Reporter:  Dan J Strohl |Owner:  nobody
 Type:  Bug  |   Status:  new
Component:  Database layer   |  Version:  2.2
  (models, ORM)  |
 Severity:  Normal   |   Resolution:
 Keywords:   | Triage Stage:
 |  Unreviewed
Has patch:  0|  Needs documentation:  0
  Needs tests:  0|  Patch needs improvement:  0
Easy pickings:  0|UI/UX:  0
-+-

Comment (by Dan J Strohl):

 Perhaps instead of using "hasattr(value, 'resolve_expression')", a
 "issubclass(value, ):" could be used?

-- 
Ticket URL: 
Django 
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.08cee34c991ef21f9de7877294a4132e%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.


[Django] #30564: Cannot create custom field that returns a queryset AND uses pre_save()

2019-06-12 Thread Django
#30564: Cannot create custom field that returns a queryset AND uses pre_save()
-+-
   Reporter:  Dan J  |  Owner:  nobody
  Strohl |
   Type:  Bug| Status:  new
  Component:  Database   |Version:  2.2
  layer (models, ORM)|
   Severity:  Normal |   Keywords:
   Triage Stage: |  Has patch:  0
  Unreviewed |
Needs documentation:  0  |Needs tests:  0
Patch needs improvement:  0  |  Easy pickings:  0
  UI/UX:  0  |
-+-
 I tried creating a custom field that would store a string that was a list
 of pks, then return that as a queryset. (yes, I could probably have done
 it using a many2many field, but I was (am) trying to reduce the number of
 db queries for this.

 In any case, all seems to work OK until I implemented a def pre_save(self,
 model_instance, add) method on my custom field.

 What seems to be happening is that when the queryset comes back from the
 pre-save, it is run through the SQLInsertCompiler.prepare_value, which
 checks the value to see if it has a "resolve_expression" attrubute, which
 it assumes is then a SQL expression and then tries checking for
 "contains_column_references"... The QuerySet object DOES have the
 "resolve_expression" attribute, but does NOT have the others that are in
 the SQL expression objects.

 I suspect this doesn't come up much.

 My trace back

 Error
 Traceback (most recent call last):

 {{{
   File
 
"C:\Users\strohl\Documents\Project\Who\who_db\who_db_tests\test_model_methods.py",
 line 101, in setUp
 self.M1 = MixinTest.objects.create(name='M1')
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\manager.py", line 82, in manager_method
 return getattr(self.get_queryset(), name)(*args, **kwargs)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\query.py", line 422, in create
 obj.save(force_insert=True, using=self.db)
   File "C:\Users\strohl\Documents\Project\Who\who_db\models.py", line 132,
 in save
 super(MixinTest, self).save(*args, **kwargs)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\base.py", line 741, in save
 force_update=force_update, update_fields=update_fields)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\base.py", line 779, in save_base
 force_update, using, update_fields,
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\base.py", line 870, in _save_table
 result = self._do_insert(cls._base_manager, using, fields, update_pk,
 raw)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\base.py", line 908, in _do_insert
 using=using, raw=raw)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\manager.py", line 82, in manager_method
 return getattr(self.get_queryset(), name)(*args, **kwargs)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\query.py", line 1186, in _insert
 return query.get_compiler(using=using).execute_sql(return_id)
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\sql\compiler.py", line 1331, in execute_sql
 for sql, params in self.as_sql():
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\sql\compiler.py", line 1275, in as_sql
 for obj in self.query.objs
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\sql\compiler.py", line 1275, in 
 for obj in self.query.objs
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\sql\compiler.py", line 1274, in 
 [self.prepare_value(field, self.pre_save_val(field, obj)) for field in
 fields]
   File "C:\Users\strohl\Documents\VirtualEnv\Who\lib\site-
 packages\django\db\models\sql\compiler.py", line 1205, in prepare_value
 if value.contains_column_references:
 AttributeError: 'Query' object has no attribute
 'contains_column_references'
 }}}
 My custom field:

 {{{
 #!python
 class PkListField(Field):
 empty_strings_allowed = False
 description = "PK List"
 default_error_messages = {}

 def __init__(self, *args, max_recs=100, max_pk_size=5, sep=',',
 ordered=None, as_pks=True, model=None, manager='objects',
 pre_save_func=None, **kwargs):
 self.pk_list_model_manager = manager
 self.max_recs = max_recs
 self.max_pk_size = max_pk_size
 self.sep = sep
 self.as_pks = as_pks
 self.ordered = ordered
 self.pre_save_func = pre_save_func
 self._pk_list_model =