Yeah, that makes sense now that I think about it.  You can combine the Cast in 
the first annotate method.
Conference.objects.annotate(year_string=Cast(ExtractYear('start_date'), 
CharField())).filter(website__contains=F('year_string')).values_list('website', 
flat=True)


From: [email protected] [mailto:[email protected]] On 
Behalf Of Jakob Karstens
Sent: Tuesday, October 9, 2018 11:58 AM
To: Django users
Subject: Re: psycopg2 Substr SQL generator bug?

Unfortunately, using the `output_field` keyword argument leads to the same 
error:
>>> Conference.objects.annotate(year=ExtractYear('start_date', 
>>> output_field=CharField())).filter(website__contains=F('year'))
Traceback (most recent call last):
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 85, in _execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: function replace(double precision, unknown, unknown) 
does not exist
LINE 1: ...nces"."website"::text LIKE '%' || REPLACE(REPLACE(REPLACE((E...
                                                             ^
HINT:  No function matches the given name and argument types. You might need to 
add explicit type casts.
I wonder if that is part of the same issue?

One way I got it working was using an explicit cast in another annotation:
Conference.objects.annotate(year=ExtractYear('start_date')).annotate(year_string=Cast('year',
 
CharField())).filter(website__contains=F('year_string')).values_list('website', 
flat=True)
I wonder why this works and the other method don't work? It seems I don't 
really understand the inner workings of casting and filtering between Django 
and Postgres.

Thanks again for your help

On Tuesday, October 9, 2018 at 9:48:22 AM UTC-7, Matthew Pava wrote:
Oh, I see.
Then just use Cast, or the output_field argument .
Conference.objects.annotate(year=ExtractYear('start_date', 
output_field=CharField())).filter(website__contains=F('year'))

From: [email protected]<javascript:> 
[mailto:[email protected]<javascript:>] On Behalf Of Jakob Karstens
Sent: Tuesday, October 9, 2018 11:43 AM
To: Django users
Subject: Re: psycopg2 Substr SQL generator bug?

Thanks Matthew, I'll submit a ticket.

Unfortunately, ExtractYear does not return a string, so it seems like I would 
still need to explicitly cast the year annotation to a string:
>>> Conference.objects.annotate(year=ExtractYear('start_date')).filter(website__contains=F('year'))
Traceback (most recent call last):
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 85, in _execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: function replace(double precision, unknown, unknown) 
does not exist
LINE 1: ...nces"."website"::text LIKE '%' || REPLACE(REPLACE(REPLACE((E...
                                                             ^
HINT:  No function matches the given name and argument types. You might need to 
add explicit type casts.


On Tuesday, October 9, 2018 at 6:45:32 AM UTC-7, Matthew Pava wrote:
I would submit a ticket for that issue.
Also, instead of using string functions to  solve your problem, I would use the 
ExtractYear function.

Conference.objects.annotate(year=ExtractYear('start_date')).filter(website__contains=F('year'))


From: [email protected]<mailto:[email protected]> 
[mailto:[email protected]] On Behalf Of Jakob Karstens
Sent: Tuesday, October 9, 2018 1:47 AM
To: Django users
Subject: psycopg2 Substr SQL generator bug?

I have a model named `Conference` which has two fields: a DateField 
`start_date` and a URLField `website`.
I want to filter the rows to return all Conference's c such that: c.website 
contains c.start_date__year. I want to perform this query db-side, not Python 
side (for memory reasons), and I don't want to use a raw query (for portability 
reasons). I believe that Django does not support using field lookups on the 
right side of the equals sign in a filter clause, so my idea was to create an 
annotation to pull out the year (e.g. '2018') from the `start_date` field and 
check if the `website` field contains this annotation.

To verify that I could get the year strings correctly as an annotation, I ran 
this statement:

Conference.objects.annotate(year_string=Substr(Cast('start_date', CharField()), 
1, length=4)).values_list('year_string', flat=True)

It successfully returned:
<PolymorphicQuerySet ['2018', '2018', '2018', '2018', '2018', '2018', '2018', 
'2018', '2018', '2018', '2018', '2018', '2018', '2018', '2019', '2018', '2018', 
'2018', '2018', '2018', '...(remaining elements truncated)...']>

However, when I tried to filter by website containing year (replacing the 
`values_list` call with the `filter` call):
Conference.objects.annotate(year_string=Substr(Cast('start_date', CharField()), 
1, length=4)).filter(website__contains=F('year_string'))

a strange exception occurred, complaining about %1% in the generated SQL (I am 
using Postgres and the psycopg2 Python library for my Django project)
>>> Conference.objects.annotate(year_string=Substr(Cast('start_date', 
>>> CharField()), 1, length=4)).filter(website__contains=F('year_string'))
Traceback (most recent call last):
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 85, in _execute
    return self.cursor.execute(sql, params)
psycopg2.DataError: invalid input syntax for integer: "%1%"
LINE 1: ...E((SUBSTRING("conferences"."start_date"::varchar, '%1%', 4))...
                                                             ^




The above exception was the direct cause of the following exception:


Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/polymorphic/query.py",
 line 456, in __repr__
    return super(PolymorphicQuerySet, self).__repr__(*args, **kwargs)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/models/query.py",
 line 248, in __repr__
    data = list(self[:REPR_OUTPUT_SIZE + 1])
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/models/query.py",
 line 272, in __iter__
    self._fetch_all()
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/models/query.py",
 line 1179, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/polymorphic/query.py",
 line 56, in _polymorphic_iterator
    o = next(base_iter)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/models/query.py",
 line 53, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, 
chunk_size=self.chunk_size)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/models/sql/compiler.py",
 line 1064, in execute_sql
    cursor.execute(sql, params)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 100, in execute
    return super().execute(sql, params)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, 
executor=self._execute)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 85, in _execute
    return self.cursor.execute(sql, params)
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/utils.py",
 line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File 
"/Users/jakobkarstens/confir/virt/lib/python3.6/site-packages/django/db/backends/utils.py",
 line 85, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.DataError: invalid input syntax for integer: "%1%"
LINE 1: ...E((SUBSTRING("conferences"."start_date"::varchar, '%1%', 4))...

What is going on? Why is the generated SQL "%1%" and not "1"? Is this a 
psycopg2 bug? Am I missing something?
Thanks in advance
--
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 [email protected]<mailto:[email protected]>.
To post to this group, send email to 
[email protected]<mailto:[email protected]>.
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/083dae62-9ad7-484c-b10b-d6d1c3c7cb52%40googlegroups.com<https://groups.google.com/d/msgid/django-users/083dae62-9ad7-484c-b10b-d6d1c3c7cb52%40googlegroups.com?utm_medium=email&utm_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 [email protected]<javascript:>.
To post to this group, send email to [email protected]<javascript:>.
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/8326add2-3815-425a-bbaa-8bcdf80cd0a5%40googlegroups.com<https://groups.google.com/d/msgid/django-users/8326add2-3815-425a-bbaa-8bcdf80cd0a5%40googlegroups.com?utm_medium=email&utm_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 
[email protected]<mailto:[email protected]>.
To post to this group, send email to 
[email protected]<mailto:[email protected]>.
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/391faad9-696a-437d-af80-dcd453225dff%40googlegroups.com<https://groups.google.com/d/msgid/django-users/391faad9-696a-437d-af80-dcd453225dff%40googlegroups.com?utm_medium=email&utm_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 [email protected].
To post to this group, send email to [email protected].
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/e8e29d82f37d49f98bea210ca512c036%40ISS1.ISS.LOCAL.
For more options, visit https://groups.google.com/d/optout.

Reply via email to