django ORM join statements - django

I'm learning django queryset API and it's so overwhelming. I'm used to sql statement and I just want a basic join statement where 2 tables join together
How can i get this result in shell?
SELECT e.emp_lastname,e.emp_firstname,o.job_description
FROM hs_hr_employee e
INNER JOIN ohrm_job_title o ON e.job_title_code = o.id
WHERE e.work_station='101';
hs_hr_employee
from django.db import models
class HsHrEmployee(models.Model):
emp_number = models.AutoField(primary_key=True)
employee_id = models.CharField(max_length=50, blank=True, null=True)
emp_lastname = models.CharField(max_length=100)
emp_firstname = models.CharField(max_length=100)
job_title_code = models.ForeignKey('OhrmJobTitle', models.DO_NOTHING,
db_column='job_title_code', blank=True, null=True)
work_station = models.ForeignKey('OhrmSubunit', models.DO_NOTHING,
db_column='work_station', blank=True, null=True)
hs_hr_job_title
class OhrmJobTitle(models.Model):
job_title = models.CharField(max_length=100)
job_description = models.CharField(max_length=400, blank=True,
null=True)
i added the models

You can filter with:
qs = HsHrEmployee.objects.filter(
work_station_id=101
).select_related('job_title_code')
For the HsHrEmployee model objects that arise from this queryset, you can then determine the job_title for example with:
for item in qs:
print(item.job_title_code.job_title)

Related

Querying django models to include and exclude items

I currently have 2 models as such
class Recipe(models.Model):
account = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, blank=True)
name = models.TextField(null=True, blank=True)
slug = models.SlugField(null=False, blank=True, unique=True)
image_path = models.ImageField(upload_to=MEDIA_URL, null=True, blank=True)
description = models.TextField(null=True, blank=True)
date_added = models.DateField(auto_now_add=True)
class RecipeIngredients(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, null=True)
ingredient = models.TextField(null=True, blank=True)
quantity = models.CharField(max_length=10, null=True, blank=True)
type = models.CharField(max_length=50, null=True, blank=True)
I am trying to do a query where if I have a list of say 2 or more items, say
ingredients = ["egg", "bacon", "rice"]
That it returns to me only the recipes that have exactly egg, bacon, and rice, or less.
I was able to do this in a hacky way, but it is really slow and not using the ORM correctly I feel.
ingredients = ["egg", "bacon", "rice"]
results = []
recipes = []
for i in ingredients:
r = RecipeIngredients.objects.filter(ingredient__icontains=i)
results.append(r)
for result in results:
for r in result:
recipes.append(r.recipe)
for r in recipes:
recipeingredients = r.recipeingredients_set.all()
for ri in recipeingredients:
ingredient = ri.ingredient
if ingredient not in ingredients:
try:
recipes.remove(r)
except:
print(r)
print("end of recipe")
Any help on how to make this a more correct query would be appreciated.
You can use raw sql, something like this:
recipe_list = Recipe.objects.raw('select a.*
from app_Recipe a
inner join app_RecipeIngredients b
on a.id = b.recipe_id and b.ingredient in ("egg", "bacon", "rice")
group by a.*
having count(*) >= 2')
maybe replace app_ with your project name, replace a.* with list of column names.

Joining more than 2 tables for reports in django and extract all the fields from the joined table

I am joining the ClientDetails, AssignmentTable and CallDetails table to get a view as to which telecaller a particular client has been assigned to and get the latest call details as well. However I am unable to accomplish that using django ORM.
ISSUE:
I am trying to access the fields inside the assignment table and call table but I am getting only the ids and not the other fields.
Question:
How do I extract all the columns from the assignment and call details table which has the client id as 1?
This is the SQL Query that I am trying to come up with:
SELECT t1.uid, t1.phone_number, t1.client_name, t1.base, t1.location, t2.assigner, t2.bpo_agent, t2.cro_agent, t3.bpo_status_id, t3.cro_status_id, t3.agent_id_id
FROM public.bpo_app_clientdetails t1
LEFT JOIN public.bpo_app_assignmentdetails t2 ON t1.uid = t2.client_id_id
LEFT JOIN public.bpo_app_calldetails t3 ON t1.uid = t3.client_id_id;
Below is the model file:
class ClientDetails(models.Model):
uid = models.AutoField(primary_key=True)
phone_number = PhoneNumberField(unique=True)
client_name = models.CharField(max_length=50, blank=True, null=True)
base = models.CharField(max_length=50, blank=True, null=True)
location = models.CharField(max_length=50, blank=True, null=True)
class Meta:
verbose_name_plural = "Client Contact Detail Table"
def __str__(self):
return f"{self.phone_number}, {self.client_name}"
class AssignmentDetails(models.Model):
uid = models.AutoField(primary_key=True)
client_id = models.ForeignKey(
ClientDetails,
on_delete=models.PROTECT,
related_name='assignment_details'
)
date_and_time = models.DateTimeField(auto_now_add=True, blank=True)
assigner = models.ForeignKey(
User,on_delete=models.PROTECT,
related_name='AssignerAgent',
db_column='assigner',
)
bpo_agent = models.ForeignKey(
User,on_delete=models.PROTECT,
related_name='bpoAgent',
db_column='bpo_agent',
)
cro_agent = models.ForeignKey(
User,on_delete=models.PROTECT,
related_name='croAgent',
db_column='cro_agent',
)
class Meta:
verbose_name_plural = "Client Assignment Detail Table"
def __str__(self):
return f"{self.uid}"
class CallDetails(models.Model):
uid = models.AutoField(primary_key=True)
date_and_time = models.DateTimeField(auto_now_add=True, blank=True)
client_id = models.ForeignKey(
ClientDetails,
on_delete=models.PROTECT,
related_name='call_details'
)
agent_id = models.ForeignKey(EmployeeDetails_lk,on_delete=models.PROTECT)
bpo_status = models.ForeignKey(BpoStatus_lk,on_delete=models.PROTECT, blank=True, null=True)
cro_status = models.ForeignKey(CroStatus_lk,on_delete=models.PROTECT, blank=True, null=True)
required_loan_amt = models.CharField(max_length=50, blank=True, null=True)
remarks = models.CharField(max_length=500, blank=True, null=True)
loan_program = models.ForeignKey(LoanProgram_lk, on_delete=models.PROTECT, blank=True, null=True)
disbursement_bank = models.ForeignKey(Banks_lk, on_delete=models.PROTECT, limit_choices_to={'loan_disbursement_status': True}, blank=True, null=True)
class Meta:
verbose_name_plural = "Client Call Detail Table"
def __str__(self):
return f"{self.uid}"
>>> qry=ClientDetails.objects.values('assignment_details','call_details').filter(uid=1)
>>> qry
<QuerySet [{'assignment_details': 1, 'call_details': None}]>
>>> print(a.query)
SELECT "bpo_app_assignmentdetails"."uid", "bpo_app_calldetails"."uid" FROM "bpo_app_clientdetails" LEFT OUTER JOIN "bpo_app_assignmentdetails" ON ("bpo_app_clientdetails"."uid" = "bpo_app_assignmentdetails"."client_id_id") LEFT OUTER JOIN "bpo_app_calldetails" ON ("bpo_app_clientdetails"."uid" = "bpo_app_calldetails"."client_id_id") WHERE "bpo_app_clientdetails"."uid" = 1
You can use prefetch_related() to achieve this. I just use some sample models here for better understanding.
class Company(models.Model):
name = models.CharField(null=True, blank=True, max_length=100)
class Project(models.Model):
name = models.CharField(null=True, blank=True, max_length=100)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
class Employee(models.Model):
name = models.CharField(null=True, blank=True, max_length=100)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
In your views.py function write the below lines to get the desired results
companies = Company.objects.filter(id=1).prefetch_related('project_set', 'employee_set')
for company in companies:
print(company.project_set.values()) # This will print this company projects
print(company.employee_set.values()) # This will print this company employees
Note: If you use related_name in your ForeignKey relationship, make sure that you access with that name instead of model_set inside prefetch_related()

Django - SImple left join between 2 tables

I have been searching for LEFT JOIN of Django on Stackoverflow, however, most of solution are just too complicated.
My models:
class Voucher(models.Model):
code = models.CharField(unique=True, max_length=255)
delivery_type = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True, null=True)
start_at = models.DateTimeField()
end_at = models.DateTimeField()
discount_type = models.CharField(max_length=255)
discount_amount = models.FloatField(blank=True, null=True)
class VoucherCustomer(models.Model):
voucher_code = models.OneToOneField(Voucher, models.DO_NOTHING, db_column='voucher_code', primary_key=True)
customer_id = models.IntegerField()
times_used = models.BigIntegerField(blank=True, null=True)
created_at = models.DateTimeField(blank=True, null=True)
updated_at = models.DateTimeField(blank=True, null=True)
This is what I tried:
from django.db.models.sql.datastructures import Join
#I thought this one is like
from VoucherCustomer left join Voucher
on VoucherCustomer.voucher_code = Voucher.code
j=Join(VoucherCustomer, 'voucher_code',
Voucher,"LEFT JOIN" ,'code', True)
j.objects.filter(voucher_code ='SAIGONS247').values('code', 'delivery_type', 'description', 'times_used').values
However, I got this result in the end:
AttributeError: 'str' object has no attribute 'get_joining_columns'
If you are having a ForeignKey or OneToOne Relationship, you can access the related object's attributes directly using double underscores.
j = VoucherCustomer.objects.filter(voucher_code__code ='SAIGONS247')
j.values('voucher_code__code', 'voucher_code__delivery_type', 'voucher_code__description', 'times_used')

How to join Objects in Django with Foreign Keys 2 tables deep

I have 2 models each with foreign keys to 2 tables. I'm trying to join the 1st table to the 3rd.
Here are my models:
Model 1:
class AppBillingBil(models.Model):
id_bil = models.AutoField(primary_key=True)
idtrp_bil = models.ForeignKey(AppTradingPartnerTrp, models.DO_NOTHING, db_column='idtrp_bil', blank=True,
null=True)
idcst_bil = models.ForeignKey(AppCustomerCst, models.DO_NOTHING, db_column='idcst_bil')
idbtp_bil = models.ForeignKey(AppBillingTypeBtp, models.DO_NOTHING, db_column='idbtp_bil')
class Meta:
db_table = 'app_billing_bil'
ordering = ['id_bil']
Model 2:
class AppCustomerCst(models.Model):
id_cst = models.AutoField(primary_key=True)
is_active_cst = models.BooleanField()
name_cst = models.CharField(max_length=50, blank=True, null=True)
Model 2:
class AppTradingPartnerTrp(models.Model):
id_trp = models.AutoField(primary_key=True)
tpid_trp = models.CharField('TPID', max_length=50, blank=True, null=True)
name_trp = models.CharField('Name', max_length=50)
Final Model Needed:
class AppCustomerTpRel(models.Model):
id_rel = models.AutoField(primary_key=True)
idcst_rel = models.ForeignKey(AppCustomerCst, models.DO_NOTHING, db_column='idcst_rel')
idtrp_rel = models.ForeignKey(AppTradingPartnerTrp, models.DO_NOTHING, db_column='idtrp_rel')
cust_vendor_rel = models.CharField(max_length=50, blank=True, null=True)
I need to join on the following criteria:
idtrp_bil__id_trp = idtrp_rel
idcst_bil__id_cst = idcst_rel
And I need to be able to use the cust_vendor_rel field from AppCustomerTpRel in a filter query on AppBillingBil
After reading the docs here: https://docs.djangoproject.com/en/3.0/topics/db/queries/#spanning-multi-valued-relationships I tried this, and was successful:
idcst_bil__appcustomertprel__cust_vendor_rel
I realized I needed to include the target model name in the value grab.

Django Joins Query

I have a Ride and Vehicle table where
class Ride(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
vehicle = models.ForeignKey(Vehicle, blank=True, null=True, unique=False)
state = models.CharField(max_length=255, blank=True, null=True)
I want to return a list of vehicles, where their LAST ride.state is NOT equal to COMPLETED
Is there a way to do this via the ORM?
from django.db.models import Max, F
Vehicle.objects.annotate(last_ride_id=Max("ride__id")).filter(ride_id=F("last_ride_id").exclude(ride__state="COMPLETE").distinct()
not tested but should work