django jsonfield querying on a value which is an array - django

I have this model:
class InventoryItem(models.Model):
size_range = JSONField(null=True) # JSONField in Django 1.9
I populated following data in it:
InventoryItem.objects.create(size_range={'size': ['S', 'M', 'L']})
But When I do following query:
InventoryItem.objects.filter(size_range__size__contains='S')
I get following error:
django.db.utils.DataError: invalid input syntax for type json
LINE 1: ..._inventoryitem"."size_range" -> 'size' #> 'S' LIMIT ...
^
DETAIL: Token "S" is invalid.
CONTEXT: JSON data, line 1: S
How do I perform the query correctly using .filter() method?
This is the SQL query above .filter() method generates:
'SELECT "app_name_inventoryitem"."id",
"app_name_inventoryitem"."size_range", FROM
"app_name_inventoryitem" WHERE
"app_name_inventoryitem"."size_range" -> \'size\' #> S'
How do I perform the query correctly using .filter() method? Thanks in advance.

As mentioned in the documentation that contains operator accepts any JSON rather than just a dictionary of strings.
https://docs.djangoproject.com/en/dev/ref/contrib/postgres/fields/#containment-and-key-operations
you can do like the following
InventoryItem.objects.filter(size_range__size__contains=['S'])
This will return the object and if you do something like the following
InventoryItem.objects.filter(size_range__size__contains=['K'])
It will return an empty queryset.
You can do the following also:
InventoryItem.objects.filter(size_range__size__contains=['S', 'M'])
This will return your the object as well.

I haven't used django in a while, but, could this be what you where looking for?
InventoryItem.objects.filter(size_range__size__contains=['S'])

Related

Write Django QuerySet that remove all whitespace from specific Keys within a JSONFIELD

I would like to write a Django QuerySet that removes whitespaces from Specific Keys within a JsonField.
I have a django model with a JsonField type.
MyModel(Model):
a: str,
properties: JSONField
this is an example of database lines :
a, properties
“first”, {“key_1”: “ key1value”, “key_2”:”key2value”, “key_3”: “ key_3”}
“second”, {“key_2”: “ key2 “}
and my queryset should update my data removing whitespace of specific key. So for Key_1 and Key_2 it will give me:
“first”, {“key_1”: “key1value”, “key_2”:”key2value”, “key_3”: “ key_3”}
“second”, {“key_2”: “key2“}
I tried using
MyModel.objects.update(properties_key_1=F("propertieskey_1”).strip().lower(), propertieskey_2=F("properties_key_2”).strip().lower())
but I get an error:
==> result 
AttributeError: 'F' object has no attribute 'strip
I tried:
MyModel.objects.update(properties__key_1=RawSQL("properties->key_1->value", []).strip())
==> result 'RawSQL' object has no attribute 'strip'
I tried:
MyModel.objects.update(properties__key_1=RawSQL("TRIM(properties->asset_class->value)”)
==> 
 SyntaxError: positional argument follows keyword argument
Any idea please ?
thx you

`op_name` parameter for `graphene_django`

The django graphene documentation shows a test example like this:
class MyFancyTestCase(GraphQLTestCase):
def test_some_query(self):
response = self.query(
'''
query {
myModel {
id
name
}
}
''',
op_name='myModel'
)
content = json.loads(response.content)
# This validates the status code and if you get errors
self.assertResponseNoErrors(response)
# Add some more asserts if you like
...
They don't have any API documentation for what op_name is, and what we should set it as. I tried to set it to my query name, but get the error:
[{'message': 'Unknown operation named "myQuery".'}]
Operation name is only needed when there are multiple operations in the query string. You only have one operation so the default (None) is fine.
https://docs.graphene-python.org/en/latest/execution/execute/#operation-name
As per my comment:
If the query is a mutation or named query, you must supply the op_name. For annon queries ("{ ... }"), should be None (default)
I am not sure how to create a "named query" with django graphene, but apparently my query is NOT a named query. Leaving op_name as None got my query to work via my unit test.

Django annotate count in JSONField with Postgres

Using Django I have a field which is of type JSONField. I am wanting to get a distinct count on a nested key/value in the json. With a normal field you can just do soemthing like the following
model.objects.values('field_name')\
.annotate(total=Count('field_name')).order_by('-total')
This does not work for a JSONField.
Example Model
class Pet(models.Model):
data = JSONField()
Example of data
{
'name':'sparky',
'animal':'dog',
'diet':{
'breakfast':'biscuits',
'dinner':'meat',
}
}
Trying
Pet.objects.values('data__diet__dinner')\
.annotate(total=Count('data__diet__dinner')).order_by('-total')
Exception of
TypeError: unhashable type: 'list'
What is the correct way to execute this?
You can use jsonb_extract_path_text via a Func object as an alternative to the field transform:
Pet.annotate(dinner=Func(
F('data'), Value('diet'), Value('dinner'),
function='jsonb_extract_path_text')) \
.values('dinner') \
.annotate(total=Count('dinner'))
The reason why the field transform data__diet__dinner fails is an error within Django when you go deeper than just one level into the json structure and use GROUP BY in the SQL. The first level (name, animal, diet) should work fine.
The reason seems to be that for nested transforms, Django changes the SQL syntax used, switching from a single value to a list to specify the path into the json structure.
This is the syntax used for non-nested json transforms (= first level):
"appname_pet"."data" -> 'diet'
And this is the syntax used for nested transforms (deeper than first level):
"appname_pet"."data" #> ARRAY['diet', 'dinner']
While constructing the query, Django chokes on that list while working out the required GROUP BY clauses. This does not seem to be an inevitable restriction; the support for transforms is quite new, and this is possibly one of the kinks that haven't been worked out yet. So if you open a Django ticket, this might just work a few versions down the line.

Is it possible to query Django objects by their FileField's url attribute

I have a Django class with a FileField. I know that you can get the FileField's url, or path, by calling filefield.path, or filefield.url . I tried to query for all of those objects by their FileField's url using
media = MediaLibraryFile.objects.filter(media_file__url='some_key')
but I get this error.
Unsupported lookup 'url' for FileField or join on the field not permitted.
I looked around the web, and found that you can only use lookup fields on foreignkey related objects, so my question is how can you query objects by file field url if thats the case ? It seems like this would be a very common query performed.
This is what I get when I do a simple query on media_file with icontains
In[27]: MediaLibraryFile.objects.all()[0].media_file.url
Out[27]: '/media/2017/6/13/444e35c2-0432-479a-805d-c46638ee3600.jpg'
In [28]: MediaLibraryFile.objects.filter(media_file__contains='/media/2017/6/13/444e35c2-0432-479a-805d-c46638ee3600.jpg')
Out[28]: <QuerySet []>
If you know exactly what you want to match you could do;
MediaLibraryFile.objects.filter(media_file__exact='some_key')
Or alternatively you could do a query like;
MediaLibraryFile.objects.filter(media_file__contains='some')
Just beware, the above is case sensitive. If you don't know the case, you can do filter(media_file__icontains='something')
The docs for field lookups are here; https://docs.djangoproject.com/en/2.0/topics/db/queries/#field-lookups

Invalid literal for int() with base 10: 'csv'

I'm trying to export the user details from the auth_user table to a CSV file in the Django admin panel. I have written the export to CSV function correctly and it has worked fine with other tables of mine. I have also provided the function location in urls.py correctly as:
(r'^auth/user//csv/', 'catalyst_db.catalyst.utils.admin_user_export'),
But Django has provided me the error saying that:
ValueError at /auth/user/csv/ invalid literal for int() with base 10: 'csv'
Any ideas to overcome this problem?
You probably have a previous URL in your urlconf which is matching the CSV value before it gets to that pattern.
I believe you have a date(User model has a join date field) inside the csv file that you are trying to upload.The date field may be corrupt,most probably contains an aphotrophe before the date entry.(You can see the aphostrophe in the formula bar).
This can be fixed by the find and replace of your spreadsheet application.
Replace ^. with & in regular expression mode.