how to optimize the query here with select_related? - django

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

Related

Django filter queryset of a models that are related with a foreign key to other model?

I have a simple question.
I have two models(Waiter and Manager) and they both contains same foreign key to restaurant as:
class Managers(BaseUser):
restaurant = models.ForeignKey(Restaurants, on_delete=models.CASCADE)
class Waiters(BaseUser):
restaurant = models.ForeignKey(Restaurants, on_delete=models.CASCADE)
And restaurant model:
class Restaurants(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(max_length=250)
location = models.CharField(max_length=200)
rating = models.DecimalField(null=True, decimal_places=2, max_digits=5)
So I need to get all waiters that restaurant=managers__restaurant_id.
I think in SQL would be:
select *
From Waiters w
Left outer join Managers m
On w.restaurant_id = m.restaurant_id
Note*
I'm able to query that like below:
manager = Managers.objects.filter(id=request.usr.id)
queryset=Waiters.objects.filter(restaurant=manager.restaurant_id)
But is there any way that i could do it in one query.
But is there any way that i could do it in one query.
This is in one query, but it will work with a subquery is probably not that efficient.
You can however filter in a more compact way with:
Waiters.objects.filter(restaurant__managers=request.user.id)
We can look "through" relations by using double underscores (__). Here we thus are looking for Waiters objects for which it restaurant is related to a Managers object with the given id of request.user.id.
how about this??
queryset = Managers.objects.filter(id=request.usr.id and Waiters.objects.filter(restaurant=manager.restaurant_id))

multiple joins on django queryset

For the below sample schema
# schema sameple
class A(models.Model):
n = models.ForeignKey(N, on_delete=models.CASCADE)
d = models.ForeignKey(D, on_delete=models.PROTECT)
class N(models.Model):
id = models.AutoField(primary_key=True, editable=False)
d = models.ForeignKey(D, on_delete=models.PROTECT)
class D(models.Model):
dsid = models.CharField(max_length=255, primary_key=True)
class P(models.Model):
id = models.AutoField(primary_key=True, editable=False)
name = models.CharField(max_length=255)
n = models.ForeignKey(N, on_delete=models.CASCADE)
# raw query for the result I want
# SELECT P.name
# FROM P, N, A
# WHERE (P.n_id = N.id
# AND A.n_id = N.id
# AND A.d_id = \'MY_DSID\'
# AND P.name = \'MY_NAME\')
What am I trying to achieve?
Well, I’m trying to find a way somehow be able to write a single queryset which does the same as what the above raw query does. So far I was able to do it by writing two queryset, and use the result from one queryset and then using that queryset I wrote the second one, to get the final DB records. However that’s 2 hits to the DB, and I want to optimize it by just doing everything in one DB hit.
What will be the queryset for this kinda raw query ? or is there a better way to do it ?
Above code is here https://dpaste.org/DZg2
You can archive it using related_name attribute and functions like select_related and prefetch_related.
Assuming the related name for each model will be the model's name and _items, but it is better to have proper model names and then provided meaningful related names. Related name is how you access the model in backward.
This way, you can use this query to get all models in a single DB hit:
A.objects.all().select_related("n", "d", "n__d").prefetch_related("n__p_items")
I edited the code in the pasted site, however, it will expire soon.

Best and fastest method to add only unique records based on certain fields in Django

I have a model with multiple fields where data is text type for the most part. I want to put a validation that from now on if a new record is being added, it should be unique based on 3 fields. Here one of the fields is a one-to-many field as is in another table.
I can try fetching all the records and start checking them using for-loop. I tried using annotate but it seems to help if the record is already in the table, but I want to do this validation before adding. I need a fast method for this validation.
class Product(models.Model):
brand = models.TextField(default='{}', null=True)
sub_brand = models.CharField(null=True)
.
.
.
class ProductNetWeight(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='product_net_weight')
net_weight = models.CharField(null=True)
First you modify your model to guarantee uniqueness like this:
class Product(models.Model):
brand = models.TextField(default='{}', null=True)
sub_brand = models.CharField(null=True)
.
.
.
class Meta:
unique_together = ['brand', 'sub_brand']
Then when inserting a new product for example un can use get_or_create like this:
product, created = Product.objects.get_or_create(brand='my brand', sub_brand='my sub brand')
If the product already exists, it will be returned in product and created is going to be False, otherwise it will return a new product and created is going to be True

Can I save a query set for django manytomayfield

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)

django model field like view

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)