I have two tables.
class DibbsSpiderDibbsMatchedProductFieldsDuplicate(models.Model):
nsn = models.TextField()
nsn2 = models.TextField()
cage = models.TextField()
part_number = models.TextField()
company_name = models.TextField(blank=True, null=True)
supplier = models.TextField(db_column='Supplier', blank=True, null=True) # Field name made lowercase.
cost = models.CharField(db_column='Cost', max_length=15, blank=True, null=True) # Field name made lowercase.
list_price = models.CharField(db_column='List_Price', max_length=15, blank=True, null=True) # Field name made lowercase.
gsa_price = models.CharField(db_column='GSA_Price', max_length=15, blank=True, null=True) # Field name made lowercase.
hash = models.TextField()
nomenclature = models.TextField()
technical_documents = models.TextField()
solicitation = models.CharField(max_length=32)
status = models.CharField(max_length=16)
purchase_request = models.TextField()
issued = models.DateField()
return_by = models.DateField()
file = models.TextField()
vendor_part_number = models.TextField()
manufacturer_name = models.TextField(blank=True, null=True)
product_name = models.TextField(blank=True, null=True)
unit = models.CharField(max_length=15, blank=True, null=True)
class Meta:
managed = False
db_table = 'dibbs_spider_dibbs_matched_product_fields_duplicate'
class DibbsSpiderSolicitation(models.Model):
line_items = models.IntegerField()
nsn = models.TextField()
nomenclature = models.TextField()
technical_documents = models.TextField()
purchase_request = models.TextField()
class Meta:
managed = False
db_table = 'dibbs_spider_solicitation'
What will be the equivalent django query for the inner join of two tables on the column nsn?
My views function will be like
def inner(request,nsn):
u_m = DibbsSpiderDibbsMatchedProductFieldsDuplicate.objects.filter(nsn2__icontains=id)
c_m = DibbsSpiderSolicitation.objects.filter(nsn__icontains=id)
obj = .......................
context = {'obj':obj}
return render(request,,"a.html",context)
the queryset should return the combination of two tables according to the common nsn.
the obj should return the combination of u_m and c_m. If u_m contains only one rows and c_m contains many rows then the obj must replicate the values of u_m.
You can try some of the options:
Adding foreign key constraint and use select_related as per this post
Raw query as mentioned in this stackoverflow post and another post with custom joins
3. Using IN query as per the following logic:
DibbsSpiderDibbsMatchedProductFieldsDuplicate.objects.filter(
nsn2__in=DibbsSpiderSolicitation.objects.filter(nsn__icontains='text_to_search').values('origin'))
First, great model names. Let's alias them:
DibbsSpiderDibbsMatchedProductFieldsDuplicate is Apples; DibbsSpiderSolicitation is Oranges
inner_qs = Apples.objects.all().extra(
tables=("yourapp_oranges",),
where=("yourapp_apples.nsn=yourapp_oranges.nsn",),
)
The documentation mentions that this api will be deprecated:
https://docs.djangoproject.com/en/4.0/ref/models/querysets/#extra
Option #1 - Introduce a ForeignKey (Recommended):
Under the class DibbsSpiderDibbsMatchedProductFieldsDuplicate add:
fkey = models.ForeignKey('DibbsSpiderSolicitation')
then you can easily access their join:
obj = DibbsSpiderDibbsMatchedProductFieldsDuplicate.Objects.filter(fkey__nsn).select_related()
Now it is your choice what you wish to do with nsn2
Option #2 - without a ForeigKey:
Raw SQL:
obj = DibbsSpiderDibbsMatchedProductFieldsDuplicate.objects.extra(where = ['''SELECT *
FROM DibbsSpiderSolicitation
INNER JOIN DibbsSpiderDibbsMatchedProductFieldsDuplicate
ON DibbsSpiderSolicitation.nsn = DibbsSpiderDibbsMatchedProductFieldsDuplicate.nsn2;'''])
# or
obj = DibbsSpiderDibbsMatchedProductFieldsDuplicate.objects.raw('''SELECT *
FROM DibbsSpiderSolicitation
INNER JOIN DibbsSpiderDibbsMatchedProductFieldsDuplicate
ON DibbsSpiderSolicitation.nsn = DibbsSpiderDibbsMatchedProductFieldsDuplicate.nsn2;''')
Using filter:
obj = DibbsSpiderSolicitation.objects.filter(nsn__in=DibbsSpiderDibbsMatchedProductFieldsDuplicate.objects.nsn2)
Sorry, I was not able to test any.
Related
views
company = Company.objects.get(id = company_id) # getting input from django urls (<int:company_id>)
vehicles = CompanyContainVehicles.objects.filter(company_id=company.id) # Give all rows having same id (company.id)
all_vehicles = Vehicle.objects.filter(companies=company) # Gives all row with id provide by company
all_vehicles_parts = VehiclePart.objects.filter(__________) # Not Working
models
class Company(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(blank=True, null=True, unique=True)
description = models.TextField()
class Vehicle(models.Model):
vehicle_number = models.IntegerField()
name = models.CharField(max_length=255)
slug = models.SlugField(blank=True, null=True, unique=True)
companies = models.ManyToManyField(
Company,
through='CompanyVehicle',
related_name='companies'
)
class CompanyVehicle(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class VehiclePart(models.Model):
id = models.AutoField(primary_key=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
type = models.ForeignKey(PartType, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
How do I get VehiclePart's with their Vehicle? (I think I will give all the data in a variable and we should divide it and add it with their Vehicle). Also, what can we do to access data if VehiclePart contains a child class named VehiclePartDetail?
I think I will give all the data in a variable and we should divide it and add with their Vehicle.
You don't have to. Django can read ForeignKey relations in reverse. You can query with:
qs = Vehicle.objects.prefetch_related('vehiclepart_set')
then you can enumerate over the queryset, and for each Vehicle object, access this with .vehiclepart_set.all(). For example:
for item in qs:
print(vehicle_name)
for part in item.vehiclepart_set.all():
print(part.id)
I want to be able to do queries involving multiple inner joins using Django ORM, here's my model (showing only relevant fields)
class Students(models.Model):
class Status(models.IntegerChoices):
preRegistered = 0 #No ha aceptado terminos y condiciones
Enabled = 1
Disabled = 2
Suspended = 3
Test = 4
id = models.AutoField(primary_key=True)
user = models.ForeignKey(Users, on_delete=models.CASCADE)
trainingPath = models.ForeignKey(trainingPaths, on_delete=models.CASCADE)
status = models.IntegerField(choices=Status.choices, default=0)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Students'
class trainingPaths(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=70, blank=False, null=False)
shortName = models.CharField(max_length=10, blank=True)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Training_Path'
class Courses(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=70, blank=False, null=False)
path = models.URLField(max_length=500, blank=True, null=True)
shortName = models.CharField(max_length=6, blank=True)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
course_image = models.URLField(max_length=200, blank=True)
class Meta():
db_table = 'Courses'
class CoursesXTrainingP(models.Model):
id = models.AutoField(primary_key=True)
trainingPath = models.ForeignKey(trainingPaths, on_delete=models.CASCADE)
course = models.ForeignKey(Courses, on_delete=models.CASCADE)
alternativeName = models.CharField(max_length=70, blank=True)
order = models.PositiveIntegerField(blank=False)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Courses_X_Training_Paths'
I want to get the information of the courses that a student has according to the value of the "trainingPath".
this is my SQL query
select
courses.id, courses.`name`, courses.course_image
from
students
join
courses_x_training_paths
on
students.trainingPath_id = courses_x_training_paths.trainingPath_id
join
courses
on
courses_x_training_paths.course_id = courses.id
where
students.trainingPath_id=1;
I have tried several ways and none of them have worked, could you please help me?
You can filter with:
Courses.objects.filter(
coursesxtrainingp__trainingPath_id=1
)
The join on the Students model is not necessary, since we already know that the trainingPath_id is one by filtering on the CoursesXTrainingP model.
Note: normally a Django model is given a singular name, so Student instead of Students.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: modification_date instead of modificationDate.
I have following models, with many to many table, for which I would like to get first 20 news from every category in single response.
class Category(models.Model):
code = models.CharField(primary_key=True, max_length=45)
name = models.CharField(max_length=200, blank=True, null=True)
is_active = models.TextField(blank=True, null=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'category'
verbose_name_plural = 'Categories'
class News(models.Model):
source_code = models.CharField(max_length=45, blank=True, null=True)
title = models.CharField(max_length=1000, blank=True, null=True)
image = models.CharField(max_length=2000, blank=True, null=True)
link = models.CharField(max_length=1000, blank=True, null=True)
published_at = models.DateTimeField(blank=True, null=True)
scraped_at = models.DateTimeField(blank=True, null=True)
is_active = models.TextField(blank=True, null=True) # This field type is a guess.
categories = models.ManyToManyField('Category', through='NewsCategory')
class Meta:
managed = False
db_table = 'news'
verbose_name_plural = 'News'
class NewsCategory(models.Model):
news_id = models.ForeignKey(News, db_column='news_id', on_delete=models.CASCADE)
category_code = models.ForeignKey(Category, db_column='category_code', on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'news_category'
unique_together = (('news_id', 'category_code'),)
verbose_name_plural = 'NewsCategory'
My view class looks like this, and here I would like to add some logic to return 20 rows for each category, for example if I have 5 categories it should return 100 news in single request.
class NewsViewSet(viewsets.ModelViewSet):
http_method_names = ['get']
serializer_class = NewsSerializer
def get_queryset(self):
queryset = News.objects.all().order_by('-published_at')
sources = self.request.query_params.getlist('sources')
if len(sources) > 0:
queryset = queryset.filter(source_code__in=sources)
return queryset
The typical way to do this is to use a window function. Django has support for them but I don't think they allow filtering on the output of them. I think this is further complicated by the m2m field. Given it's not too complex and doesn't seem to involve user input, you might just want to use a raw query.
Here's what it might look like:
SELECT *
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY c.code ORDER BY n.published_at DESC) AS row_num
FROM appname_news n
JOIN appname_newscategory nc
ON n.id = c.news_id
JOIN appname_category c
ON nc.category_code = c.code
) sub
WHERE
row_num <= 20
And see here for Django's guide on how to actually implement this in a view:
https://docs.djangoproject.com/en/3.2/topics/db/sql/#executing-custom-sql-directly
The query to be implemented with ORM is as follows,
SELECT t2.*
FROM sub_menu AS t1
INNER JOIN sub_menu AS t2 ON (t1.sub_menu_id = t2.parent_sub_menu_id)
WHERE t1.sub_menu_id = 1;
The model is as follows,
class SubMenu(models.Model):
sub_menu_id = models.AutoField(primary_key=True)
menu = models.ForeignKey('commons.MainMenu', related_name='sub_menus', on_delete=models.CASCADE)
parent_sub_menu_id = models.IntegerField(blank=True, null=True)
name = models.CharField(max_length=50)
en_name = models.CharField(max_length=50, blank=True)
ord = models.IntegerField()
api = models.CharField(max_length=255, blank=True)
api_method = models.CharField(max_length=7, blank=True)
api_detail = models.CharField(max_length=255, blank=True)
menu_type_cd = models.CharField(max_length=5, blank=True)
menu_auth_type_cd = models.CharField(max_length=5)
is_common = models.BooleanField(default=False)
is_ns = models.BooleanField(default=False)
spc_auth = models.BooleanField(default=False)
spc_auth_cd = models.CharField(max_length=5, blank=True)
create_dt = models.DateTimeField(auto_now_add=True)
update_dt = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'sub_menu'
unique_together = ('api', 'api_method',)
Not using a raw method, Is it possible to implement with Django's ORM?
Thank you.
You should do the relationship correctly on your model: https://docs.djangoproject.com/en/3.0/ref/models/fields/#module-django.db.models.fields.related. Then the parent_sub_menu should be:
class Submenu:
parent_sub_menu = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
Then run generate & DB migration. The query below should work.
And never declare relationship like you are doing right now, use Model instead via the documentation I sent.
Django does it for you already. You can just filter the related field.
https://docs.djangoproject.com/en/3.0/topics/db/queries/#lookups-that-span-relationships
SubMenu.objects.filter(parent_sub_menu__sub_menu_id=1)
I have 2 models:
PR_Components (models.Model):
companyID = models.ForeignKey(PO_Company, blank=True, null=True)
comp_nr = models.CharField (max_length=5, blank=True, null=True)
def __str__(self):
return self.comp_nr
PR_ComponentsData (models.Model):
compID = models.ForeignKey (PR_Components, blank=False, null=True)
valid = models.DateField (max_length=10, blank=False, null=True)
comp_image = models.ImageField (upload_to="/images", blank=True, null=True)
comp_text = models.CharField (max_length=30, blank=False, null=True)
....
I want to show now in a selectbox the components number (PR_Components.comp_nr) and their current valid name (PR_Componentsdata.comp_text).
I added a manager to model PR_Components which executes a sql-query.
SELECT a.*, b1.* FROM pool_pr_components a
JOIN pool_pr_componentsdata b1 ON (a.id = b1.compID_id)
LEFT OUTER JOIN pool_pr_componentsdata b2
ON (a.id = b2.compID__id AND (b1.valid < b2.valid OR b1.valid = b2.valid
AND b1.id < b2.id)) WHERE b2.id IS NULL
Later I write forms dynamicly and add the sql-result to the field:
self.fields[field].queryset = sql_result
Until here, everything works fine.
My problem:
In the selectbox the result of the str-Method of model PR_Components is shown (=comp_nr), but I would like to show also the component name like "Component (001)".
How could I do this? It should be a solution which works for other models too, because a lot of my models have "historical" data.
Thanks a lot
Solution:
in model PR_Components we overwrite str with
def __str__(self):
related = PR_ComponentsData.objects.filter(id=self.id).last()
return "{} ({})".format (related.comp_text, self.comp_nr)