I have a model that contains a FileField. I want to search for a specific filename. How do I do it? I was trying:
MyModel.objects.get(document__name=FOO)
I got a Join on field 'document' is not permitted.
Thanks!
The attributes of a FileField are not stored in the database, and cannot be used in a query. For example, the name is simply the upload_to string plus the filename. If you want to store extra data about the file you have to put that data into other fields on the database, as the example documentation shows with a Car having a name of "57 Chevy".
Also, typically the double underscore in Django's ORM denotes following a database relationship, either a ForeignKey or a ManyToMany. So in the example ORM call you provided, I would assume that MyModel had a field document that was either a ForeignKey or ManyToMany to another model, and that other model has a field called name. Which doesn't sound like is the case.
Hope that helps some.
Do this instead:
MyModel.objects.get(document__icontains='FOO')
You can filter on document, and it'll filter by the string that is the path on disk to the file.
Related
I have a tag model, with ManyToMany field "parents" to tag model, to itself. There is also "allowed_users" field.
I need to guard a view in such a way, that the user won't see any tags in parents field, to which he is not allowed.
I try to modify queryset, removing the corresponding tags from parents. But when I change the instance, tag_instance.parents.set(my_new_list) it gets saved automatically so I'm altering the database and changing the real value of the instance.
So the general question is "how to guard my view in such a way, that object's ManyToMany field is filtered by custom logic".
Another question is "how to set manytomany field without altering database", as this would be a solution to the former one.
yes I use DRF
You can use the Prefetch object to filter related table when SQL queries are executed.
For instance:
Tag.objects.preftech_related(Prefetch("parents", queryset=Tag.objects.filter(allowed_users=current_user).distinct()))
This will prefetch "parents" (meaning no additionnal sql query will run when accessing my_tag.parent.all()) and filter parents to keep only those with the current user in allowed_user
Note: Tag.objects.filter(allowed_users=current_user) will duplicate tag entries for each user in allowed_user, ence the .distinct() to keep one of each
Is there a way to query an object, 'extract' a nested piece of data from a JSONField field and then make it available as a custom, temporary field on each instance of the Queryset?
In my use case, I'm storing overflow metadata from Twitter's API in a data field for later use. I'd like to be able to access the nested field followers_count within TwitterPost.data.
I've read the docs about how to filter based on nested values but not how to extract it as a temporary field when generating a queryset.
Similarly, I've read the annotate docs for ways to create a custom temporary field but the examples all use aggregation functions on simple fields, so not JSONFields.
Thanks in advance for any suggestions.
Example model:
from django.contrib.postgres.fields import JSONField
class TwitterPost(models.Model):
id = models.IntegerField()
data = JSONField()
Example JSON value for the data field:
{
'followers_count': 7172,
"default_profile_image": false,
"profile_text_color": "000000"
}
Pseudocode for what I'd like to be able to do:
TwitterPost.objects.annotate(followers_count=instance.data.followers_count)
This is probably a late answer, but there is a way to do it
from django.contrib.postgres.fields.jsonb import KeyTransform
TwitterPost.objects.annotate(followers_count=KeyTransform('followers_count', 'data'))
OR KeyTextTransform could be used instead of KeyTransform (for converting to string)
If you want to access the data inside a JSONField, you've to use __. In your example it will be something like this
TwitterPost.objects.annotate(followers_count=instance.data__followers_count)
Take a look to the documentation here
I have a model with some HStoreField attributes and I can't seem to use Django's ORM HStoreField to query those values using LIKE.
When doing Model.objects.filter(hstoreattr__values__contains=['text']), the queryset only contains rows in which hstoreattr has any value that matches text exactly.
What I'm looking for is a way to search by, say, te instead of text and those same rows be returned as well. I'm aware this is possible in a raw PostgreSQL query but I'm looking for a solution that uses Django ORM.
If you want to check value of particular key in every object if it contains 'te', you can do:
Model.objects.filter(hstoreattr__your_key__icontains='te')
If you want to check if any key in your hstore field contains 'te', you will need to create your own lookup in django, because by default django won't do such thing. Refer to custom lookups in django docs for more info.
As far as I can remember, you cannot filter in values. If you want to filter in values, you have to pass a column and value you are referencing to. When you want it to be case insensitive use __icontains.
Although you cannot filter by all values, you can filter by all keys. Just like you showed in your code.
If you want to search for 'text' in all objects in key named let's say 'fo' - just do smth like this:
Model.objects.filter(hstoreattr__icontains={'fo': 'text'})
I want to attach a field value (id) to a QS like below, but Django throws a 'str' object has no attribute 'lookup' error.
Book.objects.all().annotate(some_id='somerelation__id')
It seems I can get my id value using Sum()
Book.objects.all().annotate(something=Sum('somerelation__id'))
I'm wondering is there not a way to simply annotate raw field values to a QS? Using sum() in this case doesn't feel right.
There are at least three methods of accessing related objects in a queryset.
using Django's double underscore join syntax:
If you just want to use the field of a related object as a condition in your SQL query you can refer to the field field on the related object related_object with related_object__field. All possible lookup types are listed in the Django documentation under Field lookups.
Book.objects.filter(related_object__field=True)
using annotate with F():
You can populate an annotated field in a queryset by refering to the field with the F() object. F() represents the field of a model or an annotated field.
Book.objects.annotate(added_field=F("related_object__field"))
accessing object attributes:
Once the queryset is evaluated, you can access related objects through attributes on that object.
book = Book.objects.get(pk=1)
author = book.author.name # just one author, or…
authors = book.author_set.values("name") # several authors
This triggers an additional query unless you're making use of select_related().
My advice is to go with solution #2 as you're already halfway down that road and I think it'll give you exactly what you're asking for. The problem you're facing right now is that you did not specify a lookup type but instead you're passing a string (somerelation_id) Django doesn't know what to do with.
Also, the Django documentation on annotate() is pretty straight forward. You should look into that (again).
You have <somerelation>_id "by default". For example comment.user_id. It works because User has many Comments. But if Book has many Authors, what author_id supposed to be in this case?
I've got 2 existing models that I need to join that are non-relational (no foreign keys). These were written by other developers are cannot be modified by me.
Here's a quick description of them:
Model Process
Field filename
Field path
Field somethingelse
Field bar
Model Service
Field filename
Field path
Field servicename
Field foo
I need to join all instances of these two models on the filename and path columns. I've got existing filters I have to apply to each of them before this join occurs.
Example:
A = Process.objects.filter(somethingelse=231)
B = Service.objects.filter(foo='abc')
result = A.filter(filename=B.filename,path=B.path)
This sucks, but your best bet is to iterate all models of one type, and issue queries to get your joined models for the other type.
The other alternative is to run a raw SQL query to perform these joins, and retrieve the IDs for each model object, and then retrieve each joined pair based on that. More efficient at run time, but it will need to be manually maintained if your schema evolves.