I am doing this:
p = MyModel.objects.filter(user__username="me").annotate(friend_count=Count(friends))
when I look at:
p[0]._meta.get_all_field_names()
It returns everything defined on the model but not the annotated field 'friend_count'
Is there a function I can use to see all the annotated fields of a particular model instance?
Use this:
p.query.annotations.keys()
It will give the list of all annotated fields.
annotations are just stored as plain instance attributes (just like the values for the ORM fields FWIW). You can use dir(my_model_instance) to see all the attributes (class and instance ones) names, or my_model_instance.__dict__.keys() for the plain instance attributes only.
Related
Let say I have two fields in a django form country and state.I want the values of state to relatively change with the values of country.i.e. I want the state field to list out the states of the country that user has selected. Also the state field should be empty during form initiation.I know that this can be done using java script and other scripts.But,I would like to know if there are any conventional methods exists in django to do the same.???
Sounds like you need to create a model for Country and State.
State model should have a foreign key linking to Country. This means many states can be related to one country. Then, populate the tables with all countries and states you want.
In your form, you can override the 'init' method with custom behavior. So, if you have declared a field 'state' then you can do something like self.fields['state'].choices = State.object.filter(country_id=some_country_id). This assumes you have some_country_id already and you can pass this through as a kwarg during instantiation.
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 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?
Lets say I have 2 django models like this:
class Spam(models.Model):
somefield = models.CharField()
class Eggs(models.Model):
parent_spam = models.ForeignKey(Spam)
child_spam = models.ForeignKey(Spam)
Given the input of a "Spam" object, how would the django query looks like that:
Limits this query based on the parent_spam field in the "Eggs" table
Gives me the corresponding child_spam field
And returns a set of "Spam" objects
In SQL:
SELECT * FROM Spam WHERE id IN (SELECT child_spam FROM Eggs WHERE parent_spam = 'input_id')
I know this is only an example, but this model setup doesn't actually validate as it is - you can't have two separate ForeignKeys pointing at the same model without specifying a related_name. So, assuming the related names are egg_parent and egg_child respectively, and your existing Spam object is called my_spam, this would do it:
my_spam.egg_parent.child_spam.all()
or
Spam.objects.filter(egg_child__parent_spam=my_spam)
Even better, define a ManyToManyField('self') on the Spam model, which handles all this for you, then you would do:
my_spam.other_spams.all()
According to your sql code you need something like this
Spam.objects.filter(id__in= \
Eggs.objects.values_list('child_spam').filter(parent_spam='input_id'))
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.