Django - Join 3 tables to get records - python

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

Related

Get data from Inherit Model Django

Im working in my Python Django ecommerce project.Now i have 2 classes Item and BookItem :
class Item(models.Model):
item_name = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200,unique=True)
description = models.TextField(max_length=500, blank=True)
price = models.IntegerField()
images = models.ImageField(upload_to='photos/products')
stock = models.IntegerField()
is_available = models.BooleanField(default = True)
category = models.ForeignKey(Category,on_delete = models.CASCADE)
created_date = models.DateTimeField(auto_now=True)
modified_date= models.DateTimeField(auto_now=True)
def __str__(self):
return self.item_name
def get_url(self):
return reverse('item_detail',args=[self.category.slug, self.slug])
class BookItem(Item):
book = models.ForeignKey(Book,on_delete = models.CASCADE)
I want to get BookItem data from the class Item.Anyone knows how to do it ?
Get Book data for all Items
Item.objects.all().values(
"book__book_name",
"book__import_price",
# "class_name__field_name", structure of the query
)
To filter Item data using Book fields
[filter Items where book name is 'bookname']
Item.objects.filter(book__book_name="bookname")

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

Query using Joins in Django

class Students(models.Model):
id = models.BigAutoField(primary_key=True)
admission_no = models.CharField(max_length=255)
roll_no = models.CharField(unique=True, max_length=50, blank=True, null=True)
academic_id = models.BigIntegerField()
course_parent_id = models.BigIntegerField()
course_id = models.BigIntegerField()
first_name = models.CharField(max_length=20)
middle_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
user_id = models.BigIntegerField()
date_of_birth = models.DateField(blank=True, null=True)
date_of_join = models.DateField(blank=True, null=True)
class Courses(models.Model):
id = models.BigAutoField(primary_key=True)
parent_id = models.IntegerField()
course_title = models.CharField(max_length=50)
slug = models.CharField(unique=True, max_length=50)
tenant_user = models.ForeignKey('Users', models.DO_NOTHING, default='')
course_code = models.CharField(max_length=20)
course_dueration = models.IntegerField()
grade_system = models.CharField(max_length=10)
is_having_semister = models.IntegerField()
is_having_elective_subjects = models.IntegerField()
description = models.TextField()
status = models.CharField(max_length=8)
created_at = models.DateTimeField(blank=True, null=True)
updated_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = True
db_table = 'courses'
def __unicode__(self):
return self.course_title
class StudentProfileSerializer(ModelSerializer):
class Meta:
model = Students
depth = 0
fields = '__all__'
The first two tables/class contains the course and student table and the third contains the serializer. Can anyone please help how to query using the joins in django. I need to fetch the course_title from Courses table and first_name from Students table.
IMHO, you should review your models; course_id in Students should be a course=models.ForeignKey('Courses', ...); this way you can refer to the course title using dot notation;
student=Student.objects.filter(pk=...)
to refer to your required fields:
student.last_name, student.course.course_title
Besides, if I understood your models, you could get some incongruence... what if the value stored in course_parent_id in Students model is different from the value stored in parent_id in Courses model? maybe the first one is redundant.
To query a field from a related object use a double underscore. So you could do
Student.objects.filter(**kwargs).values('first_name', 'last_name', 'course__course_name')

Getting other tables Django filter/select_related

I am trying to filter values using Django's filter and select_related. I am able to get the base item, but I can't get any of the joined fields.
item = Items.objects.filter(tests__company_user_id__user_id=user_id).filter(item_id=item_id).select_related("tests__company_user").values()
My goal is to get data from the user associated with the item onto the item return. Is this possible?
The data model looks like this:
class Items(models.Model):
item_id = models.CharField(primary_key=True,max_length=100)
mailed_date = models.DateTimeField()
received_date = models.DateTimeField()
last_viewed = models.DateTimeField()
dateitemsent = models.DateTimeField()
itemsent = models.CharField(max_length=25)
itemret = models.CharField(max_length=25)
dateitemret = models.DateTimeField()
status = models.CharField(max_length=25)
class Tests(models.Model):
tests_id = models.CharField(primary_key=True, unique=True, max_length=100)
teststypetest_id = models.ForeignKey(TestsType)
dateitemord = models.DateTimeField()
testdate = models.DateTimeField()
teststypetest_id = models.ForeignKey(TestsType)
dateitemord = models.DateTimeField()
testdate = models.DateTimeField()
status = models.CharField(max_length=100)
item_id = models.ForeignKey(Kits)
company_user_id = models.ForeignKey(CompanyUser)
class CompanyUser(models.Model):
user_id = models.CharField(primary_key=True,max_length=100)
username = models.CharField(max_length=254,default="empty")
sec_question_1 = models.CharField(max_length=254)
sec_answer_1 = models.CharField(max_length=254)
sec_question_2 = models.CharField(max_length=254)
sec_answer_2 = models.CharField(max_length=254)
sec_question_3 = models.CharField(max_length=254)
sec_answer_3 = models.CharField(max_length=254)
When you use select_related() you are caching joined object info but not retrieving, you need explicitly pull data:
item = Items.objects.filter(tests__company_user_id__user_id=user_id).filter(item_id=item_id).select_related("tests__company_user").values("tests__company_user_id__sec_question_1", "tests__company_user_id__sec_question_2", ...)
EDIT
Let's suppose you just want 2 fields from CompanyUser: sec_question_1 and sec_question_2:
from django.db.models import F
item = Items.objects.filter(tests__company_user_id__user_id=user_id).filter(item_id=item_id).select_related("tests__company_user").values().annotate(q1=F('tests__company_user_id__sec_question_1'), q2=F('tests__company_user_id__sec_question_2'))

Pulling Data From Multiple Tables in Django

I'm kind of new to Django and am having some trouble pulling from existing tables. I'm trying to pull data from columns on multiple joined tables. I did find a solution, but it feels a bit like cheating and am wondering if my method below is considered proper or not.
class Sig(models.Model):
sig_id = models.IntegerField(primary_key=True)
parent = models.ForeignKey('self')
state = models.CharField(max_length=2, db_column='state')
release_id = models.SmallIntegerField(choices=releaseChoices)
name = models.CharField(max_length=255)
address = models.CharField(max_length=255, blank=True)
city = models.CharField(max_length=255, blank=True)
zip = models.CharField(max_length=10, blank=True)
phone1 = models.CharField(max_length=255, blank=True)
fax = models.CharField(max_length=255, blank=True)
email = models.EmailField(max_length=255, blank=True)
url = models.URLField(max_length=255, blank=True)
description = models.TextField(blank=True)
contactname = models.CharField(max_length=255, blank=True)
phone2 = models.CharField(max_length=255, blank=True)
ratinggroup = models.BooleanField()
state_id = models.ForeignKey(State, db_column='state_id')
usesigrating = models.BooleanField()
major = models.BooleanField()
class Meta:
db_table = u'sig'
class SigCategory(models.Model):
sig_category_id = models.IntegerField(primary_key=True)
sig = models.ForeignKey(Sig, related_name='sigcategory')
category = models.ForeignKey(Category)
class Meta:
db_table = u'sig_category'
class Category(models.Model):
category_id = models.SmallIntegerField(primary_key=True)
name = models.CharField(max_length=255)
release_id = models.SmallIntegerField()
class Meta:
db_table = u'category'
Then, this was my solution, which works, but doesn't quite feel right:
sigs = Sig.objects.only('sig_id', 'name').extra(
select = {
'category': 'category.name',
},
).filter(
sigcategory__category__category_id = categoryId,
state_id = stateId
).order_by('sigcategory__category__name', 'name')
Now since the items in filter() join the sigcategory and category models, I was able to pull category.name out by using extra(). Is this a proper way of doing this? What if I did not have the reference in filter() and the join did not take place?
SigCategory has a ForeignKey pointing at Category, so you can always get from the SigCategory to the Category simply by doing mysigcategory.category (where mysigcategory is your instance of SigCategory.
If you haven't previously accessed that relationship from that instance, doing it here will cause an extra database lookup - if you're concerned about db efficiency, look into select_related.

Categories