SQL to Queryset Django - python

i want to use this query in django, i have tried and read the django document but i still can't understand it
Sql to QuerySet Django
SELECT * FROM movie as m INNER JOIN similarity as s ON m.`movie_id` = s.first_movie WHERE `movie_id` = 1 ORDER BY `s`.`similarity_score` DESC
This is My model
from django.db import models
# Create your models here.
class Movie(models.Model):
movie_id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=200)
genres = models.CharField(max_length=200)
num_ratings = models.IntegerField(null=True)
rating_median = models.FloatField(null=True)
rating_mean = models.FloatField(null=True)
comparable = models.BooleanField(default=True)
liked = models.NullBooleanField(null=True, blank=True)
def __str__(self):
return self.title
class Similarity(models.Model):
first_movie = models.ForeignKey(Movie, related_name='first_movie', on_delete = 'CASCADE')
second_movie = models.ForeignKey(Movie, related_name='second_movie', on_delete = 'CASCADE')
similarity_score = models.FloatField()
class OnlineLink(models.Model):
movie = models.ForeignKey(Movie, on_delete = 'CASCADE')
imdb_id = models.CharField(max_length=50)
youtube_id = models.CharField(max_length=50, null=True)
tmdb_id = models.CharField(max_length=50, null=True)

You can use prefetch_related for forward foreign keys.
movies = Movie.objects.all().prefetch_related(
'first_movie'
).filter(
first_movie__id=1
).order_by(
"-similarity_score"
)
This will not create an SQL join but will do the join in Python. If you must have a join, you need to start from the other table like so:
similarities = Similarity.objects.filter(
first_movie__id=1
).order_by(
"-similarity_score"
).select_related(
'first_movie'
)
Using select_related does an inner join, so you don't hit the table every time you want to access a field from the Movie table.
See Django docs for prefetch_related and select_related.
See this StackOverflow post for prefetch_related and select_related.

A solution could be the following:
s = Similarity.objects.filter(first_movie__id=1).order_by("-similarity_score")
# and access to first_movie
for movie in s:
movie.first_movie

Related

Django: Select count of foreign key field

I have the following models:
class SystemTable(models.Model):
id = models.FloatField(primary_key=True)
system_name = models.CharField(max_length=50)
system_desc = models.CharField(max_length=200, blank=True, null=True)
system_url = models.CharField(max_length=2000, blank=True, null=True)
status = models.ForeignKey(StatusLkp, models.DO_NOTHING, db_column='status',default=1)
date_created = models.DateTimeField(default=datetime.now())
objects = models.Manager()
class Meta:
app_label = 'system_table'
managed = True
db_table = 'system_table'
class SystemPagesTable(models.Model):
id = models.FloatField(primary_key=True)
system = models.ForeignKey(SystemTable, on_delete=models.CASCADE)
page_name = models.CharField(max_length=200)
page_link_xpath = models.CharField(max_length=2000)
flag = models.FloatField(blank=True, null=True)
status = models.ForeignKey(StatusLkp, models.DO_NOTHING, db_column='status',default=1)
date_created = models.DateTimeField(default=datetime.now())
objects = models.Manager()
class Meta:
app_label = 'system_pages_table'
managed = True
db_table = 'system_pages_table'
I want to perform the following SQL query:
select
s.*,
(select count(*) from page p where p.system_id = s.id) as NUM_OF_PAGES
from system s;
How do I perform the above query with Django's ORM without having to use a for loop?
I do not want a result based on one system, I want to retrieve all systems with their page counts.
Try to use annotate:
from django.db.models import Count
System.objects.annotate(num_pages=Count('page'))

Trying to convert Left Join of SQL into Django query-set?

here is my models.py file
class Customer(models.Model):
"""All Customers details goes here"""
name = models.CharField(max_length=255, null=False)
firm_name = models.CharField(max_length=255, null=False)
email = models.EmailField(null=False)
phone_number = models.CharField(max_length=255, null=False)
location = models.CharField(max_length=255,null=True)
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
"""Meta definition for Customer."""
verbose_name = 'Customer'
verbose_name_plural = 'Customers'
def __str__(self):
"""Unicode representation of Customer."""
return self.name
class Order(models.Model):
"""All order details goes here.It has OneToMany relationship with Customer"""
STATUS = (
('CR', 'CR'),
('DR', 'DR'),
)
customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL)
bill_name = models.CharField(max_length=255, null=False)
payment_date=models.DateField(auto_now=False)
status = models.CharField(max_length=255, choices=STATUS, null=False)
amount = models.FloatField(max_length=255, null=False)
date_created = models.DateTimeField(auto_now_add=True)
description = models.TextField(null=True)
class Meta:
"""Meta definition for Order."""
verbose_name = 'Order'
verbose_name_plural = 'Orders'
def __str__(self):
"""Unicode representation of Order."""
return self.bill_name
i want to access only Customer's name and all fields of Order,in short i want to convert the following SQL in Django Query-set
select name ,bill_name ,status from accounts_customer left join
accounts_order on accounts_customer.id = accounts_order.customer_id
where accounts_order.status="DR";
To attach the customer's name on the order object, you can use annotate with an F expression. https://docs.djangoproject.com/en/3.0/ref/models/expressions/#using-f-with-annotations
orders = Order.objects.annotate(
customer_name=F('customer__name')
).filter(status='DR')
for order in orders:
print(order.customer_name)
If you suspect you will want to access more customer attributes, you may want to select_related (slightly more memory, larger query). What's the difference between select_related and prefetch_related in Django ORM?
orders = Order.objects.select_related('customer').filter(status='DR')
for order in orders:
print(order.customer.name)
You can perform join operation using two ways:
1st: via using select_related
I.e. Order.objects.select_related('customer')
And
2nd: via using filter:
I.e. Order.objects.filter(status__iexact="DR")

Django - Join 3 tables to get records

Need to join these 3 tables , can someone give me the ORM queryset . need to show the records on one template based on these three tables.
Models.py
class Item_Table(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=127)
description = models.TextField(null=True,blank=True)
qty_in_ferma_warehouse = models.IntegerField(null=True,blank=True,default=0)
status = models.BooleanField()
ListID = models.CharField(max_length=80, null=True,blank=True)
class Order_Table(models.Model):
id = models.AutoField(primary_key=True)
order_number = models.CharField(max_length=63)
notes = models.TextField()
created_at = models.DateField()
status = EnumField(Choice,max_length=2, null=True,blank=True)
Total_Amount = models.DecimalField(max_digits=18,decimal_places=2)
must_fill_in_items = models.IntegerField()
total_replenish_small_order = models.IntegerField()
order_type = EnumField(Choice3,max_length=2, null=True,blank=True)
delivery_method = EnumField(Choice6, max_length=2, null=True, blank=True)
class Orderitems_Table(models.Model):
id = models.AutoField(primary_key=True)
order_id = models.ForeignKey(Order_Table,on_delete='')
item_id = models.ForeignKey(Item_Table,on_delete='')
qty = models.IntegerField()
next_order_qty = models.IntegerField(null=True,blank=True,default=0)
Rate = models.DecimalField(max_digits=18,decimal_places=2)
Amount = models.DecimalField(max_digits=18,decimal_places=2)
status = EnumField(Choice2,max_length=2,null=True,blank=True)
accumulated_residual_item = models.IntegerField()
accumulated_damaged_item = models.IntegerField()
You can have a many to many field in Order_Table.
items = models.ManyToManyField(Person, through='Orderitems_Table')
then you can query on Order_Table model and have a queryset
you can go through the documentation to have more insights about ManyToMany Field and how to play with this
For forms and view you can follow this link

Querying Django on a derived field

Using Django 1.8
I have an unmanaged model that points to a view in the db and I'm trying to return a queryset based on a derived field.
Here is a basic example of the model structure:
class Book(models.Model):
book_id = models.IntegerField()
publisher = models.CharField(max_length=20, null=True) # Can join to Publisher.publisher_name
sku = models.CharField(max_length=15, null=True) # Can join to Sku.sku
class Meta:
managed = False
db_table = 'vw_book'
class Sku(models.Model):
sku = models.CharField(max_length=15)
publisher = models.ForeignKey('myapp.Publisher')
class Publisher(models.Model):
publisher_name = models.CharField(max_lenth=20)
region = models.ForeignKey('myapp.Region')
class Region(models.Model):
region_name = models.CharField(max_length=20)
I'm looking for a way to return a queryset of Book based on the region, derived from the publisher as the preferred field and then the sku. It is possible for these fields in Book to refer to different region fields as the data is unlcean and has been derived from multiple sources. I can add a method to the Book model to derive the region, but trying to get a queryset from this is too slow.
class Book(models.Model):
publisher = models.CharField(max_length=20, null=True)
sku = models.CharField(max_length=15, null=True)
class Meta:
managed = False
db_table = 'vw_book'
def get_region(self):
if not self.publisher:
if not self.sku:
return ''
try:
sku = Sku.objects.get(sku=self.sku)
return sku.publisher.region.region_name
except Sku.DoesNotExist:
return ''
try:
publisher = Publisher.objects.get(publisher_name=self.publisher)
return publisher.region.region_name
except Publisher.DoesNotExist:
return ''
region_dict = {}
for book in Book.objects.all():
region_dict.setdefault(book.get_region(), []).append(book.book_id)
Book.objects.filter(book_id__in=region_dict.get('UK', []))
I am unable to add an extra field to the Book model. Is there a more efficient way I can do this?
I would filter the skus and then filter books based on the skus you receive
skus = Sku.objects.filter(publisher__region__region_name=region).values_list('sku', flat=True)
Book.objects.filter(sku__in=skus)
You can do the same with publishers if need be and do an Or query.
.filter(Q(publisher__in=publishers) |Q(sku__in=skus))

Django: How to join tables based on a lookup tables' value

I am trying to do what one might consider an advanced sql query and would like to know if its possible in Django without resorting to raw sql (I will if its necessary).
I want to join 1 or another table based on a value located in a table lookup table and would like to do this entirely in python/django.
The following are rough examples of the models I am using:
class SpecificProduct(models.Model):
specific_product_id = models.AutoField(primary_key=True)
a_field = models.TextField()
something_specific_to_this_model = models.CharField()
class GeneralProduct(models.Model):
other_product_id = models.AutoField(primary_key=True)
text = models.TextField()
TABLE_CATEGORIES = {
1 : SpecificProduct,
2 : GeneralProduct,
}
class ProductCategory(models.Model):
category_id = models.AutoField(primary_key=True)
table_category = models.IntegerField() # Technically represents a table.
category_text = models.CharField(max_length=20)
class Inventory(models.Model):
inventory_id = models.AutoField(primary_key=True)
product_category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE)
product_pk = models.IntegerField() # Technically foreign key to a product table.
quantity = models.IntegerField()
What I want is a method like:
def get_product(category_id, product_pk):
# SQL query magic
return one_object_of_a_specific_product_type
This method should be able to do things like...
Give me the product (model) where the product_category = 1 and the
product_pk = 1. (returns a SpecificProduct model)
Give me the product where product_category = 2 and the product_pk = 50
(returns a GeneralProduct model)
How do you do this query in Django and is this even possible?
Edit:
Based on Kireeti K's response I have created models that look like the following:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
class SpecificProduct(models.Model):
specific_product_id = models.AutoField(primary_key=True)
specific_text = models.TextField()
class GeneralProduct(models.Model):
general_product_id = models.AutoField(primary_key=True)
text = models.TextField()
class ProductCategoryLookup(models.Model):
category_id = models.ForeignKey(ContentType, on_delete=models.CASCADE, primary_key=True)
category_text = models.CharField(max_length=20)
class Inventory(models.Model):
inventory_id = models.AutoField(primary_key=True)
product_category = models.ForeignKey(ContentType, on_delete=models.CASCADE)
product_id = models.PositiveIntegerField()
product = GenericForeignKey('product_category', 'product_id')
quantity = models.IntegerField()
def get_product(category_id, product_pk):
content_type = ContentType.objects.get(id=category_id)
inventory = Inventory.objects.get(product_category=content_type, product_id=product_pk).first()
return inventory.product
You can use a generic-foreign-key to get foreign-key relation with any model sort of dynamically, read about it here. https://docs.djangoproject.com/en/2.1/ref/contrib/contenttypes/#generic-relations
If you rewrite your models using generic-foreign-key then it looks something like this.
class ProductCategory(models.Model):
category_id = models.AutoField(primary_key=True)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
table_category = models. GenericForeignKey() # Technically represents a table.
category_text = models.CharField(max_length=20)
class Inventory(models.Model):
inventory_id = models.AutoField(primary_key=True)
product_category = models.ForeignKey(ProductCategory,
on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
product = models. GenericForeignKey() # Technically foreign key to a product table.
quantity = models.IntegerField()
Now to achieve what you want, you can implement your function like this.
def get_product(model=None, category_id, product_pk):
model = "specificproduct" if model else "generalproduct"
content_type = ContentType.objects.get(model=model)
inventory = Inventory.objects.get(product_category_id=category_id, object_id=product_pk, content_type=content_type)
return inventory.product

Categories