How do I query the length of a Django ArrayField? - django

I have an ArrayField in a model, I'm trying to annotate the length of this field ( so far without any luck)
F('field_name__len') won't work since join is not allowed inside F(). Even
ModelName.objets.values('field_name__len') is not working
Any idea?
I'm using django 1.11

The extra() function has been deprecated according to the docs:
Use this method as a last resort
This is an old API that we aim to deprecate at some point in the future. Use it only if you cannot express your query using other queryset methods.
Here is how you can do the same thing using a custom Annotation function:
from django.db import models
class ArrayLength(models.Func):
function = 'CARDINALITY'
MyModel.objects.all().annotate(field_len=ArrayLength('field')).order_by('field_len')
Note that the cardinality() function is available in PostgreSQL 9.4 or later. If you're using an older version, you have to use array_length():
MyModel.objects.all().annotate(field_len=Func(F('field'), 1, function='array_length')).order_by('field_len')
One caveat with this second query is that an empty array will be sorted in front of all non-empty ones. This could be solved by coalescing NULL values from array_length to 0.

ModelName.objects.extra(select={'length':'cardinality(field_name)'}).order_by('length')
you can try this

Tested on django 3.5, your query now works!
I'm not sure which version added this offhand, but give it a try, or try upgrading if you can.
ModelName.objects.values('field_name__len')
<ModelName [{'field_name__len': 1}]>
Also some other things to try:
ModelName.objects.filter(field_name__len__gt=0)
ModelName.objects.filter(field_name__len__gte=0)
ModelName.objects.filter(field_name__len=0)
ModelName.objects.filter(field_name__len__lte=10)
ModelName.objects.filter(field_name__len__lt=10)

Related

Postgres select function in Django annotation

I have old database and need custom select.
in sql i can use:
SELECT x(geometry) FROM table
but I dont know how to force x() function in django select.
You can create a custom function using Expressions.
class GeoX(Func):
function = 'X'
MyModel.objects.annotate(x=GeoX('field'))
This will result in the geometry X function being invoked and it's result being annotated to a field labeled x in your model. However this is the inferior solution. The better solution is to install geodjango. That provides full access to almost every single function in PostGIS. Also works with spatialite and msyql spatial extensions.
I managed to solve problem using Func()
Func(F('geometry'), function='x')

django json field: which one?

I am looking for a JSON field for Django.
I have found mainly 2 jsonfield app and I am not sure which one I should use.
The main difference I see is that the first one does not have the native JSON datatype support for PostgreSQL anymore.
It has been removed recently (https://github.com/bradjasper/django-jsonfield/commit/15957c9dab18c546ae5c119f8a6057e5db6b2135). It was related to this issue https://github.com/bradjasper/django-jsonfield/issues/57
but I am not sure if it's the right approach since JSONB is also coming soon with PostgreSQL 9.4. I think it's better to use the native datatype when using PostgreSQL. What do you think?
1) https://github.com/bradjasper/django-jsonfield
2) https://bitbucket.org/schinckel/django-jsonfield/
Since Django 1.9 JSON support is back again with JSONField:
https://docs.djangoproject.com/en/1.9/ref/contrib/postgres/fields/

Django admin URL query string "OR". Is it possible?

I love being able to write quick and dirty query strings right into the URL of the Django admin. Like: /admin/myapp/mymodel/?pub_date__year=2011
AND statements are just as easy: /admin/myapp/mymodel/?pub_date__year=2011&author=Jim
I'm wondering if it's possible to issue an 'OR' statement via the URL. Anyone heard of such functionality?
Django < 1.4 doesn't support OR queries. Sometimes it is possible to translate OR queries to __in - queries which are supported (they are equivalent to OR queries but only for single field values).
You can also upgrade to django development version: it has more versatile list_filter implementation (see https://docs.djangoproject.com/en/dev//ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter ) which can be used for providing advanced admin filters (including OR-queries).
The & is not a logical AND, even though it seems to be acting that way in your case. I'm pretty certain there is no way to create a logical OR in the GET query string.

django-non rel and dbindexer ordering property

I am working on a test project using django-nonrel.
After enabling the admin interface and adding some entities to the database, I added a search_field to the ModelAdmin class. As I tried to search I got the following error:
DatabaseError: Lookup type 'icontains' isn't supported
In order to fix this, I added an index like this:
from models import Empresa
from dbindexer.api import register_index
register_index(Empresa, {'nombre': 'icontains'})
But now I am getting the following error:
First ordering property must be the same as inequality filter property, if specified for this query; received key, expected idxf_nombre_l_icontains
Am I trying to do something that is not supported by django-nonrel and dbindex yet?
Thanks in advance for any help
I have the same problem (on another case), know the cause of it, but currently have no solution.
It is because of GAE's database limitation in which if a query contain an inequality comparison, that is ' < , > , >= ' or something like that, any ordering of any member of the entities (other than the member that use the inequality comparison) must be preceded by an ordering of the member with inequality comparison first.
If we are directly using GAE's database, this limitation can easily be overcome by first set the order by the member that use the inequality first, than sort with whatever you want to sort.
Unfortunately, the django-nonrel and djangoappengine's database wrapper seems to be unable to do that (I've tried the order by first technique using django model, still error, maybe it's just me), not to mention the use of dbindexer as the wrapper of djangoappengine.db which itself is a wrapper of GAE's database......
Bottomline, debugging can be a hell for this mess. You may want to use GAE datastore directly just for this case, or wait for djangoappengine team to come up with better alternative.
I kind of fixed it by changing the ordering property in the ModelAdmin subclass:
class EmpresaAdmin(admin.ModelAdmin):
search_fields = ('nombre',)
#order by the atribute autogenerated by dbindex
ordering = ('idxf_nombre_l_icontains',)
Does anyone know a better way to fix this?

Proper way to call a database function from Django?

i'm triyng to make a full text search with postgresql and django So I've created a function search_client(text) which returns a list of clients. To call it from the DB i use something like this:
SELECT * FROM search_client('something')
and i'm not really sure how to call it from django. i know i could do something like
cursor = connection.cursor()
cursor.execute("SELECT * FROM search_client('something')")
result = cursor.fetchall()
but that will only return a list of values, and i'd like to have a list of objects, like when i use the "filter()" method.
Any ideas?? thanks for your time!
If your goal is a full-featured search engine, have a look at django-haystack. It rocks.
As for your question, the new (Django 1.2) raw method might work:
qs = MyModel.objects.raw("SELECT * FROM search_client('something')")
If you're using Django 1.2, you can use the raw() ORM method to execute custom SQL but get back Django models. If you're not, you can still execute the SQL via the extra() method on default QuerySet, and pump it into a custom method to either then go pull the real ORM records, or make new, temporary, objects
First, you probably don't want to do this. Do you have proof that your database function is actually faster?
Implement this in Python first. When you can prove that your Python implementation really is the slowest part of your transaction, then you can try a stored procedure.
Second, you have the extra method available in Django.
http://docs.djangoproject.com/en/1.2/ref/models/querysets/#django.db.models.QuerySet.extra
Note that compute-intensive database procedures are often slow.