How to get data from two tables with DjangoORM? - django

I have two tables in the database:
class CustomerEquipment(models.Model):
serial_number = models.CharField(max_length=255)
state_timestamp = models.DateTimeField()
state_type = models.IntegerField()
class Meta:
managed = False
db_table = 'customer_equipment'
class LogCustomerEquipment(models.Model):
state = models.IntegerField()
state_timestamp = models.DateTimeField()
serial_number = models.CharField(max_length=255)
class Meta:
managed = False
db_table = 'log_customer_equipment'
I execute two database queries:
customer_equipment_list = CustomerEquipment.objects.using('portal').filter(
Q(state_type=10) & Q(state_timestamp__icontains='2020-02-27')
)
log_customer_equipment_list = LogCustomerEquipment.objects.using('portal').filter(
Q(state=2) & Q(state_timestamp__icontains='2020-02-27')
)
I need to get serial_number which are in both tables.
How to do it? How can I optimize queries? The same serial_number can be in both tables. Need to choose those that intersect.

You can try this:
set(CustomerEquipment.objects.values_list('serial_number ', flat=True)) & set(LogCustomerEquipment.objects.values_list('serial_number ', flat=True))
or maybe you should refactor models from the relation.
For example, using ForeignKey or ManyToManyField.

Related

Archive records and re-inserting new records in Django?

I've got a Stock table and a StockArchive table.
My Stock table consists of roughly that 10000 stocks that I update daily. The reason I have a StockArchive table is because I still wanna some historic data and not just update existing records. My question is, is this a proper way of doing it?
First, my models:
class Stock(models.Model):
objects = BulkUpdateOrCreateQuerySet.as_manager()
stock = models.CharField(max_length=200)
ticker = models.CharField(max_length=200)
exchange = models.ForeignKey(Exchange, on_delete=models.DO_NOTHING)
eod_price = models.DecimalField(max_digits=12, decimal_places=4)
currency = models.CharField(max_length=20, blank=True, null=True)
last_modified = models.DateTimeField(blank=True, null=True)
class Meta:
db_table = "stock"
class StockArchive(models.Model):
objects = BulkUpdateOrCreateQuerySet.as_manager()
stock = models.ForeignKey(Stock, on_delete=models.DO_NOTHING)
eod_price = models.DecimalField(max_digits=12, decimal_places=4)
archive_date = models.DateField()
class Meta:
db_table = "stock_archive"
I proceed on doing the following:
#transaction.atomic
def my_func():
archive_stocks = []
batch_size = 100
old_stocks = Stock.objects.all()
for stock in old_stocks:
archive_stocks.append(
StockArchive(
stock=stock.stock,
eod_price = stock.eod_price,
archive_date = date.today(),
)
)
# insert into stock archive table
StockArchive.objects.bulk_create(archive_stocks, batch_size)
# delete stock table
Stock.objects.all().delete()
# proceed to bulk_insert new stocks
I also wrapped the function with a #transaction.atomic to make sure that everything is committed and not just one of the transactions.
Is my thought process correct, or should I do something differently? Perhaps more efficient?

How to create complex multi model join query set with Django ORM

I want to create a query set with multiple tables. I cannot find any resource that helps
Beside some small 2 table join examples, I cannot find any resource that is helpful for this, not in stackoverflow, the Django docs or even in the ORM Cookbook.
Below is firstly the SQL I want to recreate followed by the models classes, simplified for the purpose of this question. They have in fact a LOT more fields.
SELECT doc_uid,
docd_filename,
doct_name,
docd_media_url
FROM vugd_detail,
vug_virtual_user_group,
vugdoc_vug_docs,
doc_documents,
docd_detail,
doct_type
WHERE vugd_vug_uid = vug_uid
AND vugdoc_vug_uid = vug_uid
AND vugdoc_doc_uid = doc_uid
AND docd_doc_uid = doc_uid
AND doct_uid = doc_doct_uid
AND vugd_status = 1
AND docd_status = 1
AND NOW() BETWEEN vugd_start_date AND vugd_end_date
AND NOW() BETWEEN docd_start_date AND docd_end_date
AND vug_uid = {{Some ID}};
class VugVirtualUserGroup(models.Model):
objects = None
vug_uid = models.AutoField(primary_key=True)
vug_name = models.CharField(unique=True, max_length=30)
vug_short_code = models.CharField(max_length=6)
vug_created_on = models.DateTimeField()
vug_created_by = models.CharField(max_length=30)
class Meta:
managed = False
db_table = 'vug_virtual_user_group'
app_label = 'main'
class VugdDetail(models.Model):
objects = None
vugd_uid = models.AutoField(primary_key=True)
vugd_vug_uid = models.ForeignKey(VugVirtualUserGroup, models.DO_NOTHING, db_column='vugd_vug_uid')
vugd_long_name = models.CharField(max_length=50)
vugd_status = models.IntegerField()
vugd_start_date = models.DateTimeField()
vugd_end_date = models.DateTimeField()
class Meta:
managed = False
db_table = 'vugd_detail'
app_label = 'main'
class VugdocVugDocs(models.Model):
onjects = None
vugdoc_uid = models.AutoField(primary_key=True)
vugdoc_vug_uid = models.ForeignKey(VugVirtualUserGroup, models.DO_NOTHING, db_column='vugdoc_vug_uid')
vugdoc_doc_uid = models.ForeignKey(DocDocuments, models.DO_NOTHING, db_column='vugdoc_doc_uid')
class Meta:
managed = False
db_table = 'vugdoc_vug_docs'
app_label = 'main'
class DocdDetail(models.Model):
objects = None
docd_uid = models.AutoField(primary_key=True)
docd_doc_uid = models.ForeignKey(DocDocuments, models.DO_NOTHING, db_column='docd_doc_uid')
docd_filename = models.CharField(max_length=200)
docd_media_url = models.CharField(max_length=300)
docd_status = models.IntegerField()
docd_start_date = models.DateTimeField()
docd_end_date = models.DateTimeField()
class Meta:
managed = False
db_table = 'docd_detail'
app_label = 'main'
class DoctType(models.Model):
objects = None
doct_uid = models.AutoField(primary_key=True)
doct_vug_uid = models.ForeignKey('VugVirtualUserGroup', models.DO_NOTHING, db_column='doct_vug_uid')
doct_name = models.CharField(max_length=30)
doct_start_date = models.DateTimeField()
doct_end_date = models.DateTimeField()
class Meta:
managed = False
db_table = 'doct_type'
app_label = 'main'
class DocDocuments(models.Model):
object = None
doc_uid = models.AutoField(primary_key=True)
doc_doct_uid = models.ForeignKey('DoctType', models.DO_NOTHING, db_column='doc_doct_uid')
class Meta:
managed = False
db_table = 'doc_documents'
app_label = 'main'
As one can see the actual query is not so complicated.
The goal here is just to get the list of valid(active, not deleted) files avilable for a specific VUG(Simple user group), if the group has a valid status.
So if there is any Django ORM experts who can help with what is really a common SQL type that should be should be possible to be converted to a Django ORM script, your help will sincerely be appreciated.
The Django way to query multiple related tables is to chain them using dot notation.
A sudo code example might help point you in the right direction.
vug_virtual_user_group = VugVirtualUserGroup.objects.get(vug_uid="Some ID")
print(f'vug_virtual_user_group {vug_virtual_user_group}')
A lookup using the foreign key to get all related objects
vugdoc_vugdocs = vug_virtual_user_group.vugdocvugdocs_set.all()
print(f'vugdoc_vugdocs {vugdoc_vugdocs}')
This example assumes that the default modelmanger objects is not overridden by objects = None.

select related in Django

I am trying to accomplish something very similar to:
How to join 3 tables in query with Django
Essentially, I have 3 tables. In the Django REST we are showing table 3. As you see below (models.py), table 3 has company_name which is a foreign key of table 2 and table 2 is a foreign key of table 1. Both table 2 and 3 are linked by the table 1 ID. Table 1 contains the actual text, which we want to display in the API output, not the ID number.
Table 1: Manufacturer of Car -- Table 2: What the Car is -- Table 3: list of all cars
Models.py
Table 1:
class ManufacturerName(models.Model):
name_id = models.AutoField(primary_key=True)
company_name = models.CharField(unique=True, max_length=50)
class Meta:
managed = False
db_table = 'manufacturer_name'
Table 2:
class CarBuild(models.Model):
car_id = models.AutoField(primary_key=True)
car_icon = models.CharField(max_length=150, blank=True, null=True)
company_name = models.ForeignKey('ManufacturerName', models.DO_NOTHING, db_column='ManufacturerName')
class Meta:
managed = False
db_table = 'car_build'
Table 3:
class CarList(models.Model):
list_id = models.AutoField(primary_key=True)
company_name = models.ForeignKey('CarBuild', models.DO_NOTHING, db_column='CarBuild')
title = models.CharField(unique=True, max_length=100)
description = models.TextField()
class Meta:
managed = False
db_table = 'cars'
Within my views:
This is what I am trying, based on the foreign key relationships:
queryset = CarList.objects.all().select_related('company_name__company_name')
I get no errors when I save and run this, however, the ID is still being returned, and not the text associated with the foreign key relationships:
[
{
"list_id": 1,
"company_name": "http://127.0.0.1:8000/api/1/",
"title": "Really fast car you're driving, and this is dummy text",
Again, I would like to achieve getting the text associated with the company_name foreign key relationships from table 1 to show in the JSON.
serializer and viewset
class manufacturer_name(serializers.HyperlinkedModelSerializer):
class Meta:
model = manufacturer_name
fields = ('name_id', 'company_name')
class manufacturer_name(viewsets.ModelViewSet):
queryset = manufacturer_namee.objects.all()
serializer_class = manufacturer_name
class CarBuildViewSet(viewsets.ModelViewSet):
queryset = CarBuild.objects.all()
serializer_class = CarBuildSerialiser
class CarBuildSerialiser(serializers.HyperlinkedModelSerializer):
class Meta:
model = CarBuild
fields = ('car_id', 'car_icon', 'company_name')
class CarListSerialiser(serializers.HyperlinkedModelSerializer):
class Meta:
model = News
fields = ('list_id', 'company_name', 'title')
class CarListViewSet(viewsets.ModelViewSet):
serializer_class = CarList
def get_queryset(self):
queryset = News.objects.all().select_related('company_name__company_name')
return queryset
Based on detailed conversation to clear few details. Here is the answer.
You need to make small changes to your models as it was quite confusing to understand what you want to achieve.
Models:
class ManufacturerName(models.Model):
name_id = models.AutoField(primary_key=True)
company_name = models.CharField(unique=True, max_length=50)
class Meta:
managed = False
db_table = 'manufacturer_name'
class CarBuild(models.Model):
car_id = models.AutoField(primary_key=True)
car_icon = models.CharField(max_length=150, blank=True, null=True)
manufacturer = models.ForeignKey(ManufacturerName,on_delete=models.SET_NULL)
class Meta:
managed = False
db_table = 'car_build'
class CarList(models.Model):
list_id = models.AutoField(primary_key=True)
car = models.ForeignKey(CarBuild, on_delete=models.DO_NOTHING)
title = models.CharField(unique=True, max_length=100)
description = models.TextField()
class Meta:
managed = False
db_table = 'cars'
And then You need to adjust your serializers.
class CarListSerialiser(serializers.HyperlinkedModelSerializer):
company_name= serializers.SerializerMethodField(read_only=True)
class Meta:
model = CarList
fields = ('list_id', 'company_name', 'title')
def get_company_name(self, obj):
return obj.car.manufacturer.company_name
And you use it in your view:
class CarListViewSet(viewsets.ModelViewSet):
queryset = CarList.object.all()
serializer_class = CarListSerialiser

Django queryset - column IN() GROUP BY HAVING COUNT DISTINCT

With the following models:
class Post(models.Model):
class Meta:
db_table = "posts"
class Tag(models.Model):
tag = models.CharField(max_length=50)
class Meta:
db_table = "tags"
class PostTag(models.Model):
postid = models.PositiveIntegerField()
tagid = models.PositiveIntegerField()
class Meta:
unique_together = ("postid", "tagid")
db_table = "posttags"
To get postids of posts which contain all the tagids given in TAGLIST where TAGLEN is the number of tagids in TAGLIST:
SELECT postid
FROM posttags
WHERE tagid IN (TAGLIST)
GROUP BY postid
HAVING COUNT(DISTINCT tagid) = TAGLEN
But how do I do this with Django ORM?
I found a solution.
TAGLEN = TAGLIST.count()
withtags = PostTag.objects.filter(tagid__in=TAGLIST)
withall = withtags.values("postid").annotate(tagtotal=Count("tagid", distinct=True)).order_by()
withall.filter(tagtotal=TAGLEN).values_list("postid", flat=True)
And running .query.__str__() on all this returns basically the following SQL below.
SELECT "postid"
FROM "posttags"
WHERE "tagid" IN (TAGLIST)
GROUP BY "postid"
HAVING COUNT(DISTINCT "tagid") = TAGLEN'

Django ORM query with multiple inner join

I want to be able to do queries involving multiple inner joins using Django ORM, here's my model (showing only relevant fields)
class PuntoMedida(models.Model):
id_punto_medida = models.AutoField(primary_key=True,db_column='id_punto_medida')
nombre = models.CharField(max_length=100, blank=False,db_column='nombre')
class Meta:
db_table = 'punto_medida'
class Instalacion(models.Model):
id_instalacion = models.AutoField(primary_key=True,db_column='id_instalacion')
activo = models.CharField(max_length=1, blank=False,default='1',db_column='activo')
usuarios=models.ManyToManyField(User,through='InstalacionUsuario')
class Meta:
db_table = 'instalacion'
class InstanciaInstalacion(models.Model):
id_instancia_instalacion = models.AutoField(primary_key=True,db_column='id_instancia_instalacion')
id_instalacion = models.ForeignKey(Instalacion, blank=False, null=False,db_column='id_instalacion')
puntos_medida=models.ManyToManyField('PuntoMedida',through='InstInstalacionPuntoMedida')
activo = models.CharField(max_length=1, blank=True,default='1',db_column='activo')
class Meta:
db_table = 'instancia_instalacion'
class InstInstalacionPuntoMedida(models.Model):
id= models.AutoField(primary_key=True,db_column='id')
id_instancia_instalacion = models.ForeignKey(InstanciaInstalacion,db_column='id_instancia_instalacion', blank=False, null=False)
id_punto_medida = models.ForeignKey('PuntoMedida',db_column='id_punto_medida', blank=False, null=False)
class Meta:
unique_together = ('id_instancia_instalacion','id_punto_medida')
db_table = 'instancia_instalacion_punto_medida'
class InstalacionUsuario(models.Model):
id= models.AutoField(primary_key=True,db_column='id')
id_instalacion = models.ForeignKey(Instalacion,db_column='id_instalacion', blank=False, null=False)
id_usuario = models.ForeignKey(User,db_column='id_usuario', blank=False, null=False)
class Meta:
unique_together = ('id_instalacion','id_usuario')
db_table = 'instalacion_usuario'
I want to obtain all the objects PuntoMedida related to all the objects Instalacion that a certain user can see. Until now, I've been able to do this using a raw sql like this one:
SELECT a.id_punto_medida, a.nombre
FROM punto_medida a
INNER JOIN instancia_instalacion_punto_medida b ON
a.id_punto_medida=b.id_punto_medida
INNER JOIN instancia_instalacion c ON
b.id_instancia_instalacion=c.id_instancia_instalacion
INNER JOIN instalacion d ON
c.id_instalacion=d.id_instalacion
INNER JOIN instalacion_usuario f ON
d.id_instalacion=f.id_instalacion
AND c.activo='1'
AND d.activo='1'
and f.id_usuario=7
However, I am looking forward to stop using raw queries and only use Django ORM just in case I need to change my database in the future (currently using PostgreSQL, might migrate to Oracle). I've been trying to create the equivalent ORM query with no success. Any ORM expert out there than can help me with this syntax or give me an example of where to start?Thanks in advance...
Can you try this:
PuntoMedida.objects.filter(
instanciainstalacion__activo='1',
instanciainstalacion__id_instalacion__activo='1',
instanciainstalacion__id_instalacion__instalacionusuario_set__id_usuario=7,
)