I am attempting to optimize some code. I have model with many related models, and I want to annotate and filter by the value of a field of a specific type of these related models, as they are designed to be generic. I can find all instances of the type of related model I want, or all of the models related to the parent, but not the related model of the specific type related to the parent. Can anyone advise?
I initially tried
parents = parent.objects.all()
parents.annotate(field_value=Subquery(related_model.objects.get(
field__type='specific',
parent_id=OuterRef('id'),
).value)))
But get the error This queryset contains a reference to an outer query and may only be used in a subquery. When I tried
parents = parent.objects.all()
parents.annotate(field_value=Q(related_model.objects.get(
field__type='specific',
parent_id=F('id'),
).value)))
I get DoesNotExist: related_field matching query does not exist. which seems closer but still does not work.
Model structure:
class parent(models.Model):
id = models.IntegerField(null=False, primary_key=True)
class field(models.Model):
id = models.IntegerField(null=False, primary_key=True)
type = models.CharField(max_length=60)
class related_model(models.Model):
parent = models.ForeignKey(parent, on_delete=models.CASCADE, related_name='related_models')
field = models.ForeignKey(field, on_delete=models.CASCADE, related_name='fields')
Is what I want to do even possible?
Never mind I decided to do a reverse lookup, kinda like
parent_ids = related_model.objects.filter(field__type='specific', parent_id__in=list_of_parents).values_list('parent_id')
parents.objects.filter(id__in=parents_id)
Related
I am having a very specific issue here, and am not sure how to navigate through it. So, I have a couple of serializers here, the code to which is attached below. Starting with three models, Cluster, Family and Individual, where a Cluster is a group of families, a Family is a group of individuals and an Individual is the lowest information holder.
With the help of through models(foreign keys between two models), I need to serialize and output families with their individuals containing integer fields representing a certain order defined by the through relations. As you can see, I have to use bots, Individual and Family as arguments in the returns_order function, and that's creating problems. Is there a better way that I am not aware of?
class IndividualSerializer(serializers.ModelSerializer):
order = serializers.SerializerMethodField('returns_order')
def returns_order(self, Individual, Family):
through = IndividualThroughFamily.objects.get(family=Family.id, topics=Topic.id)
order = through.order
return order
class Meta:
model = Individual
fields = ['order', 'individualName']
class FamilySerializer(serializers.ModelSerializer):
order = serializers.SerializerMethodField('returns_order')
def returns_order(self, Family):
through = FamilyThroughCluster.objects.get(family=Family.id)
order = through.order
return order
relatedIndividuals = IndividualSerializer(many=True)
class Meta:
model = Family
fields = ['order', 'familyName', 'relatedIndividuals']
I am trying to create a messaging system in Django, and I came across an issue: How could I efficiently find all messages linked in a thread?
Let's imagine I have two models:
class Conversation(models.Model):
sender = models.ForeignKey(User)
receiver = models.ForeignKey(User)
first_message = models.OneToOneField(Message)
last_message = models.OneToOneField(Message)
class Message(models.Model):
previous = models.OneToOneField(Message)
content = models.TextField()
(code not tested, I'm sure it wouldn't work as is)
Since it is designed as a simple linked list, is it the only way to traverse it recursively?
Should I try to just get the previous of the previous until I find the first, or is there a way to query all of them more efficiently?
I use Rest Framework serializer with depth. So If you have serializer with Depth value to 3. I will fetch the full model of whatever the foreign key available until three parents.
https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization
class AppliedSerializer(serializers.ModelSerializer):
class Meta:
model = Applied
fields = ("__all__")
depth = 3
I have Picture model which contains different link to images. I also have People and Car models that may have one or more images. That means that certain pictures can belong to an object in Car or People model.
I try to make ForeignKey but one of the field (car_id or people_id) will be empty.
I can't create an abstract model and make ForeignKey from Picture
The last solution that I know is genericForeignKey but it seems to complex for such trivial task.
Is there are a best way to solve the problem?
I solved the problem like this:
I created another model called Album that has only id
class People(models.Model):
name = models.CharField(max_length=100)
album = models.OneToOneField(Album)
class Car(models.Model):
horse_power = models.IntegerField()
ablum = models.OneToOneField(Album)
class Picture(models.Model):
title = models.CharField(max_length=100)
album = models.ForeignKey(Album)
Model:
class Comment(MPTTModel):
submitter = models.ForeignKey(User, blank=True, null=True)
post = models.ForeignKey(Post, related_name="post_comments")
parent = TreeForeignKey('self', blank=True, null=True, related_name="children")
text = models.CharField("Text", max_length=1000)
rank = models.FloatField(default=0.0)
pub_date = models.DateTimeField(auto_now_add=True)
Iterating through nodes has the same effect (>1000 queries).
I had similar issue with MPTT models. It was solved with select_related
(also for parent's foreign keys).
So, depending on your needs, proper queryset can looks like:
Comment.objects.select_related('post', 'submitter', 'parent', 'parent__submitter', 'parent__post')
Also, if you need comment's children in your loop as well, it can be optimized like that:
queryset.prefetch_related('children')
Or even like that:
queryset.prefetch_related(
Prefetch(
'children',
queryset=Comment.objects.select_related('post', 'etc.'),
to_attr='children_with_posts'
)
)
... and depending on tree depth, you can use that:
queryset.select_related('parent', 'parent__parent', 'parent__parent__parent')
# you got the idea:)
Duplicated queries happens because all objects from iteration hits the data base when you refer a related object.
Try using select_related in your view method.
Probably using django prefetch related or select related will resolve that, but if not work, sorry you will need a raw query.
Have you ever read about optimizing Django queries? Here is a simple tutorial that's explain a lot of things: https://docs.djangoproject.com/en/3.1/topics/db/optimization/
lets say I have a model named User, and other models representing actions done by the a user, like "User_clicked", "User_left", "User_ate_cookie" etc. etc.
the User_* models have different fields and inherit from a single abstract class (User_do_something)
my question is this:
what's the django-way of querying ALL the models, from all the relevant tables, that point on a specific user?
eg. I want to do User.get_all_actions() and get a list with mixed type of models in them, containing all the objects that inherit from User_do_something and point on the specific user.
Note: performance is critical. I don't want to make multiple db queries and combine the list, if possible, I want to do it with a single sql select.
some code to be clear:
class User(models.Model):
uuid = models.UUIDField(unique=True, default=uuid.uuid4)
creation_time = models.DateTimeField(auto_now_add=True)
def get_all_actions(self):
'''
return a list with ALL the actions this player did.
'''
??????? how do I do this query ???????
class User_do_action(models.Model):
user = models.ForeignKey(User)
creation_time = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class User_click(User_do_action):
... some fields
class User_left(User_do_action):
... some fields
class User_ate_cookie(User_do_action):
... some fields
etc. etc.
thanks!