I have Django models that looks like this
class Customer(models.Model):
name = models.CharField(_("Name"))
class Feature(models.Model):
label = models.CharField(_("Name"))
class AddOn(models.Model):
customer = models.ForeignKey(Customer)
feature = models.ForeignKey(Feature)
Given that I have an instance of Customer e.g
customer = Customer.objects.get(pk=1)
How do I get all the labels in feature in one query to avoid N+1 query?
For now what I've done is:
[addon.feature.label for addon in self.addon_set.all()]
But I think for each addon.feature will create a query that is not very optimized if there is a lot of addon
You can use values/values_list to get all labels in a single query
self.addon_set.values_list('feature__label', flat=True)
EDIT: Example of the ManyToManyField
class Customer(models.Model):
name = models.CharField(_("Name"))
features = ManyToManyField('Feature', through='AddOn')
class Feature(models.Model):
label = models.CharField(_("Name"))
class AddOn(models.Model):
customer = models.ForeignKey(Customer)
feature = models.ForeignKey(Feature)
You can then perform queries like customer_obj.features.all() or feature_obj.customers.all() and it won't affect your ability to still query the AddOn model
Related
I'm using Django 3.0.6 with Django Rest Framework 3.11.1. I'm connecting to a MongoDB database using the djongo connector. One of my models has an ArrayField that contains embedded records. I would like to know how I can retrieve these embedded fields using a django query.
Each Person can have many different sub records. Here is a sample model to illustrate what I'm working on
Models:
from djongo import models
class SubRecords(models.Model):
status = models.CharField(max_length=20)
startTime = models.CharField(max_length=20)
identifier = models.CharField(max_length=20)
job_title = models.CharField(max_length=20)
class Meta:
abstract = True
class Person(models.Model):
_id = ObjectIdField()
workplace = models.CharField(max_length=120)
subject = models.CharField(max_length=120)
records = models.ArrayField(model_container=SubRecords)
I would like to query the Person model and get
all Person.records objects and
Person.records objects that match some criteria
I have tried to do this
>>> Person.objects.filter(records__exact={'job_title': 'HR'})
Now the problem I'm facing is that the result isn't limited to subrecords where the job title is HR, instead if a Person object contains a sub record that matches the criteria, the whole Person object and associated sub records are returned.
I want to be able to get a list of all the subrecords and only the subrecords that match the criteria I specify. How can I do this?
You don't need __exact:
Person.objects.filter(records={'job_title':'HR'})
I suppose you can do it like this
Person.objects.filter(records__in={'job_title':'HR'})
You can add .all() at the end of query if you want.
i have
class A(models.Model):
field_a = models.OneToOneField(B, on_delete=models.CASCADE)
class B(models.Model):
field_b = models.charField()
how to write the most optimum query here using select_related or something else?
In my use case i need to use both, field_a of model A and field_b of model B somewhere in my code. So can i fetch both the objects in one db hit?
queryset_b = B.objects.get(field_b="some name")
queryset_a = A.objects.get(b=queryset_b).field_a
field_a_of_model = queryset_a
field_b_of_model = queryset_b.field_b
# then some manipulation with both fields
it hits the db twice. Can i do this thing in one db hit using select_related so that it fetches both object at once?
You could use lookup that span relationship
a = A.objects.get(b__field_b="some name")
This would result in single query to database
If you want single query to access fields from b too use select_related()
a = A.objects.select_related().get(b__field_b="some name")
a.field_a.field_b
I have some models that represents some companies and their structure. Also all models can generate some Notifications (Notes). User can see own Notes, and, of course, can't see others.
class Note(models.Model):
text = models.CharField(...)
class Company(models.Model):
user = models.ForeignKey(User)
note = models.ManyToManyField(Note, blank='True', null='True')
class Department(models.Model):
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
class Worker(models.Model):
department = models.ForeignKey(Department)
note = models.ManyToManyField(Note, blank='True', null='True')
class Document(models.Model)
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
The question is how I can collect all Notes for particular user to show them?
I can do:
Note.objects.filter(worker__company__user=2)
But its only for Notes that was generated by Workers. What about another? I can try hardcoded all existing models, but if do so dozen of kittens will die!
I also tried to use backward lookups but got "do not support nested lookups". May be I did something wrong.
EDIT:
As I mentioned above I know how to do this by enumerating all models (Company, Worker, etc. ). But if I will create a new model (in another App for example) that also can generate Notes, I have to change code in the View in another App, and that's not good.
You can get the Notes of a user by using the following query:
For example let us think that a user's id is 1 and we want to keep it in variable x so that we can use it in query. So the code will be like this:
>>x = 1
>>Note.objects.filter(Q(**{'%s_id' % 'worker__department__company__user' : x})|Q(**{'%s_id' % 'document__company__user' : x})|Q(**{'%s_id' % 'company__user' : x})|Q(**{'%s_id' % 'department__company__user' : x})).distinct()
Here I am running OR operation using Q and distinct() at the end of the query to remove duplicates.
EDIT:
As I mentioned above I know how to do this by enumerating all models
(Company, Worker, etc. ). But if I will create a new model (in another
App for example) that also can generate Notes, I have to change code
in the View in another App, and that's not good.
In my opinion, if you write another model, how are you suppose to get the notes from that model without adding new query? Here each class (ie. Department, Worker) are separately connected to Company and each of the classes has its own m2m relation with Note and there is no straight connection to User with Note's of other classes(except Company). Another way could be using through but for that you have change the existing model definitions.
Another Solution:
As you have mentioned in comments, you are willing to change the model structure if it makes your query easier, then you can try the following solution:
class BaseModel(models.Model):
user = models.Foreignkey(User)
note = models.ManyToManyField(Note)
reports_to = models.ForeignKey('self', null=True, default=None)
class Company(BaseModel):
class Meta:
proxy = True
class Document(BaseModel):
class Meta:
proxy = True
#And so on.....
Advantages: No need to create separate table for document/company etc.
object creation:
>>c= Company.objects.create(user_id=1)
>>c.note.add(Note.objects.create(text='Hello'))
>>d = Document.objects.create(user_id=1, related_to=c)
>>d.note.add(Note.objects.create(text='Hello World'))
I have a model suppose
class A(models.Model):
name = models.CharField(max_length=256)
class B(models.Model):
city = models.CharField(max_length=256)
users = models.ManyToManyField(A)
Now can I say if I have to save these models I can use
users = A.objects.all()
and suppose I have a data for to store as
b = B(city="XYZ", user=users).save()
that is can I use directly the complete query set to store the manytomany field data.
You can't pass a many-to-many field when you instantiate a model, in any case.
After the model is saved, though, you can do:
b.users.add(*users)
I'd like to have a model field that will return the latest related of another model.
An example-
class Thing(models.Model):
name = models.CharField(max_length=200)
state = models.ForeignKey(State, query=latest) #pure fantasy
class State(models.Model):
change = models.DateTimeField(auto_now_add=True)
thing = models.ForeignKey(Thing)
Assume that the model class State has a many to one relationship to Thing.
given- some_thing = Thing.object.all()[0]
I want some_thing.state to be the instance of State that has the most recent State.change value for the instance Thing that I have in hand.
I'd like to specify at the Django Model level an instance variable that does what I've described above. I can think of two ways to do this, but neither is at this level:
at the actual DB level -- create a view and turn off django db
syncing
(http://stackoverflow.com/questions/507795/can-i-use-a-database-view-as-a-model-in-django)
the view level -- when I create new State row manually set that row to the related Thing.state instance.
You cannot have a database level dynamic foreign key. You can, however, have a property or a method that captures your item for you:
class Thing(models.Model):
name = models.CharField(max_length=200)
#property
def state(self):
return State.objects.latest('change')
class State(models.Model):
change = models.DateTimeField(auto_now_add=True)
thing = models.ForeignKey(Thing)