don't want inner joins on django models - django

i've migrated an existing database that i would like to work with django. i have the following models:
class Device(models.Model):
class Meta:
db_table = u'DEVICES'
managed=False
id = models.CharField(primary_key=True, max_length=22, db_column='DEVICE_ID')
name = models.CharField(max_length=40, db_column='DEVICE_NAME')
status = models.CharField(max_length=10, db_column='STATUS')
class DevicePort(models.Model):
class Meta:
db_table = u'DEVICE_PORT'
managed=False
id = models.CharField( primary_key=True, max_length=22, db_column='DEVICE_PORT_ID')
device = models.OneToOneField(Device, db_column='DEVICE_ID')
type = models.CharField( max_length=22, db_column='PORT_TYPE_ID')
port_num = models.CharField( max_length=30, db_column='DEVICE_PORT_NUM')
class IP(models.Model):
class Meta:
db_table = u'IP_NODE'
managed=False
ip_address = models.CharField(primary_key=True, max_length=15, db_column='IP_NODE_NO')
hostname = models.CharField(max_length=40, db_column='IP_HOST')
port = models.OneToOneField(DevicePort, db_column='DEVICE_PORT_ID')
status = models.CharField(max_length=50, db_column='IP_NODE_STATUS')
i want a list of Devices and their relational IP.ip_address and IP.hostnames. In SQL, i would do something like:
SELECT UNIQUE
d.device_name device
FROM
IP_NODE c,
DEVICES d,
DEVICE_PORT e
WHERE
c.ip_node_no = b.ip_node_no
AND c.device_port_id = e.device_port_id
AND e.device_id = d.device_id
AND d.device_name LIKE 'something';
How do i do this with my django models?

So instead of an inner join you want...and implicit join? Is there something I'm missing here because an implicit join is slower than an explicit one most all cases.
[http://postgresql.1045698.n5.nabble.com/explicit-JOIN-faster-than-implicit-td1920335.html][1]
I can't see any reason you would want to do this, but as stated above you can certainty get this by writing your own queries with raw, or even connection.cursor. Maybe even could pull it off with extra(tables=[...]), though I'm not positive as I've never used tables like this.

Related

How to create one to many generic relation between objects in Django

I have these two models:
How do I correctly set the relationship so I can do backward queries?
class Client(models.Model):
city = models.CharField(max_length=16)
worker = models.ForeignKey(
"Worker",
null=True,
default="1",
on_delete=models.SET_DEFAULT,
related_name="assigned_workers",
)
class Meta:
abstract = True
And:
class Worker(models.Model):
first_name = models.CharField(max_length=16)
last_name = models.CharField(max_length=16)
gender = models.CharField(max_length=1)
What I want to do is set up the models in a way I can do the following queries:
Query the clients assigned to a worker using the worker object. Something like this:
Worker.objects.assigned_workers.all()

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.

Nested Query / not directly related field in Django

If the models are as follows,
class Subject(BaseModel):
name = models.CharField(db_column='name', max_length=200, blank=False, null=False, unique=True)
class Meta:
managed = True
db_table = 'Subject'
class Topic(BaseModel):
name = models.CharField(db_column='name', max_length=200, blank=False, null=False, unique=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, null=False, related_name='subject_topic')
class Meta:
managed = True
db_table = 'Topic'
class Question(BaseModel):
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, null=False, related_name='question_topic')
class Meta:
managed = True
db_table = 'Question'
How can I make a query Question for a subject.
questions = Question.objects.filter(topic_in=Topic.objects.get(subject=subject).only('id').all())
but it's not working. Any help would be really great help.
Your current "inner queryset" won't give you multiple values, it only returns 1.
Topic.objects.get(subject=subject).only('id').all()
You are using .objects.get() which returns a model instance, so for example .only() or .all() on that won't work unless your model has such a defined function.
Furthermore you don't really need 2 querysets, you can get your result with only one:
my_subject_ids = [...] # these are the ids of Subject models you want
Question.objects.filter(topic__subject_id__in=my_subject_ids)
You can also query for Subject.name, just use the following for this: topic__subject__name__in=my_list.
If you want to query for a specific Subject-instance you can use topic__subject=my_obj.
You also might wanna take a look at the docs for more information on that.

Django Models relation with primary key add extra "_id" to the column

These are my two models, when I try to open City page on Django I get an error: "column city.country_id_id does not exist". I don't know why python adds extra _id there.
class Country(models.Model):
country_id = models.CharField(primary_key=True,max_length=3)
country_name = models.CharField(max_length=30, blank=True, null=True)
class Meta:
managed = False
db_table = 'country'
class City(models.Model):
city_id=models.CharField(primary_key=True,max_length=3)
city_name=models.CharField(max_length=30, blank=True, null=True)
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
Because if you construct a foreign key, Django will construct a "twin field" that stores the primary key of the object. The foreign key itself is thus more a "proxy" field that fetches the object.
Therefore you normally do not add an _id suffix to the ForeignKey:
class City(models.Model):
city_id = models.CharField(primary_key=True,max_length=3)
city_name = models.CharField(max_length=30, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
It however might be better for unmanaged tables, to specify a db_column=… parameter [Djang-doc] in the ForeignKey:
class City(models.Model):
city_id = models.CharField(primary_key=True,max_length=3)
city_name = models.CharField(max_length=30, blank=True, null=True)
country = models.ForeignKey(Country, db_column='country_id', on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
With this parameter you make it explicit how the column is named at the database side.
this is due to Django's behind the scenes magic.
The fields documentation is very clear about that and I highly recommend you read the Foreign Key section in the link below:
https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ForeignKey
Basically, when you want to access the Country reference in the if a City instance, you would do it like this:
city.country_id
I also recommend another naming convention for your Foreign Key fields. Instead of <modelname>_id = models.ForeignKey... just call it <modelname> = models.ForeignKey...
Hope this helps, happy coding

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,
)