How can I do INNER JOIN in Django in legacy database? - python

Sorry for probably simple question but I'm a newby in Django and really confused.
I have an ugly legacy tables that I can not change.
It has 2 tables:
class Salespersons(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
xsin = models.IntegerField()
name = models.CharField(max_length=200)
surname = models.CharField(max_length=200)
class Store(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
xsin = models.IntegerField()
brand = models.CharField(max_length=200)
So I suppose I can not add Foreign keys in class definitions because they change the tables.
I need to execute such sql request:
SELECT * FROM Salespersons, Store INNER JOIN Store ON (Salespersons.xsin = Store.xsin);
How can I achieve it using Django ORM?
Or I'm allowed to get Salespersons and Store separately i.e.
stores = Store.objects.filter(xsin = 1000)
salespersons = Salespersons.objects.filter(xsin = 1000)

Given your example query, are your tables actually named Salespersons/Store?
Anyway, something like this should work:
results = Salespersons.objects.extra(tables=["Store"],
where=["""Salespersons.xsin = Store.xsin"""])
However, given the names of the tables/models it doesn't seem to me that an inner join would be logically correct. Unless you always have just 1 salesperson per store with same xsin.

If you can make one of the xsin fields unique, you can use a ForeignKey with to_field to generate the inner join like this:
class Salespersons(models.Model):
xsin = models.IntegerField(unique=True)
class Store(models.Model):
xsin = models.ForeignKey(Salespersons, db_column='xsin', to_field='xsin')
>>> Store.objects.selected_related('xsin')

I don't see why you can't use the models.ForeignKey fields even if the database lacks the constraints -- if you don't explicitly execute the SQL to change the database then the tables won't change. If you use a ForeignKey then you can use Salespersons.objects.select_related('xsin') to request that the related objects are fetched at the same time.

Related

create Self Referencing Table using peewee

I am failing to find a way I can create a self-referencing table using peewee. I am trying to create an entity similar to one on this article.
I have tried this solution here and it doesn't seem to give me the results that I want.
class Customer(Model):
name = TextField()
class CustomerDepartment(Model):
refid = ForeignKeyField(Customer, related_name='customer')
id = ForeignKeyField(Customer, related_name='department')
These are documented here: http://docs.peewee-orm.com/en/latest/peewee/models.html#self-referential-foreign-keys
class Department(BaseModel):
parent = ForeignKeyField('self', null=True, backref='children')
name = CharField()
Example use:
root = Department.create(name='root')
d1 = Department.create(parent=root, name='Dept 1')
# etc.

How to use values and distinct on different field on Django ORM?

currently I have terms on my applications and one user can have a lot of terms registered, and my current model is like this
class Term(models.Model):
id = models.UUIDField("id", default=uuid.uuid4, editable=False, primary_key=True)
user_id = models.PositiveIntegerField("user id", default=None)
name = models.CharField()
sometimes I need to do a query to get all the users who have terms registered, so I do the following query:
Term.objects.filter(active=True)
.order_by("user_id")
.values("user_id")
.distinct()
and this is enough to solve my problems, but now I'll change my model and it will look like this:
class Term(models.Model):
id = models.UUIDField("id", default=uuid.uuid4, editable=False, primary_key=True)
user_id = models.PositiveIntegerField("user id", default=None)
name = models.CharField()
shared_with = ArrayField(models.PositiveIntegerField("id do usuario"), blank=True) # New
How you can see, I've added a new field named shared_with, that basically is a array of user ids which I want to share terms, So now I need to make a query who will return all ids who can have terms registered (shared_with included). So if i register a Term with user_id = 1 and shared_with = [2,3], my query need to return [1,2,3].
I've solved this problem today with the following code, but I think I can do this just using django ORM and one query:
users = set()
for user in (
Term.objects.filter(active=True)
.order_by("user_id")
.values("user_id")
.distinct()
):
users.add(user["user_id"])
for user in (
Term.objects.filter(active=True)
.order_by("user_id")
.values("shared_with")
):
for user_id in user["shared_with"]:
users.add(user_id)
print(users) # {1,2,3}
If someone knows how to do it and can share the knowledge, I will be grateful.
I don't recommend using the PositiveIntegerField and ArrayField as relations between tables, you can use ForeignKey and ManyToManyField instead, in your case what I understand is a user can have many Terms and a Term can be shared among many users, so the perfect solution is to add ManyToManyField in your User model
class User(AbstarctUser):
... (your fields)
terms = models.ManyToManyField(Term, related_name="users")
and Term model will be like:
class Term(models.Model):
id = models.UUIDField("id", default=uuid.uuid4, editable=False, primary_key=True)
name = models.CharField(max_length=200)
active = models.BooleanField(default=True)
... (other fields)
in that case, if you want to extract user ids with active terms, you can get it as following :
users = User.objects.filter(terms__active=True).distinct().values_list("id", flat=True)

Django ORM multiple tables query

I trying to make some queries in Django ORM (migration from SQL). My models looks like this
class Iv2(models.Model):
s_id = models.AutoField(primary_key=True)
l_eid = models.CharField(max_length=265)
t_id = models.CharField(max_length=265,unique=True)
class Sv2(models.Model):
id = models.AutoField(primary_key=True)
s_id = models.OneToOneField(Iv2, on_delete=models.PROTECT)
gdd = models.DateTimeField(default=datetime.now)
class Ev2(models.Model):
id = models.OneToOneField(Iv2, to_field='l_eid', on_delete=models.PROTECT)
s_id = models.ForeignKey(Iv2, on_delete=models.PROTECT)
car = models.CharField(max_length=265)
I want to write a query, given t_id(some real search value). I want to get the corresponding Sv2.gdd and Ev2.car
I'm thinking to get s_id and l_eid with the t_id. And when I get s_id. I can query Sv2 and with l_eid I can query Ev2.
Is it possible to achieve everything with one ORM query ? can prefetch/select_related work here?
"Given t_id of Iv2 get Sv2.gdd and Ev2.car"
First get the Sv2 instance by filtering its 1:1 relation by the
real search value t_id:
sv2 = Sv2.objects.filter(s_id__t_id=t_id).first()
sv2.gdd
Now you have 2 options to get Ev2.car
Add related name in Ev2 (more on related_name here )
Assuming your related_name is ev2 you can do:
sv2.ev2.car
Use the default django related_name modelname__set
sv2.ev2_set

how to make left join in django?

this is my first model
class DipPegawai(models.Model):
PegID = models.AutoField(primary_key=True)
PegNamaLengkap = models.CharField(max_length=100, blank=True, null=True)
PegUnitKerja = models.IntegerField(null=True,blank=True)
and this is my second model
class DipHonorKegiatanPeg(models.Model):
KegID = models.AutoField(primary_key=True)
PegID = models.ForeignKey(DipPegawai, blank=True,null=True)
KegNama = models.Charfield(max_length=100,null=True,blank=True)
i want to make left join with this model, something like this in mysql query
SELECT PegNamaLengkap, KegNama_id
FROM karyawan_dippegawai AS k LEFT JOIN honorkegiatanpeg_diphonorkegiatanpeg AS h ON k.PegID = h.PegID_id
WHERE PegUnitKerja = 3
GROUP BY k.PegID
how to make left join with django orm same like mysql query above?
Should be something like:
DipPegawai.objects.filter(PegUnitKerja=3).values_list.('pegnamalengkap', 'diphonorkegiatanpeg_kegnama')
Tell me if that worked for you.
You can print your raw query using print(your_var_here.query). Remember put your query into a var
DipHonorKegiatanPeg.objects.filter(PegID__PegUnitKerja=3).values('PegID__PegNamaLengkap', 'KegNama_id')

how to let django achieve inner join

there are two tables:
class TBLUserProfile(models.Model):
userid = models.IntegerField(primary_key=True)
relmusicuid = models.IntegerField()
fansnum = models.IntegerField()
class TSinger(models.Model):
fsinger_id = models.IntegerField()
ftbl_user_profile = models.ForeignKey(TBLUserProfile, db_column='Fsinger_id')
I want to get Tsinger info and then order by TBLUserProfile.fansnum, I know how to write sql query: select * from t_singer INNER JOIN tbl_user_profile ON (tbl_user_profile.relmusicuid=t_singer.Fsinger_id) order by tbl_user_profile.fansnum, but I don't want to use model raw function. relmusicuid is not primary key otherwise I can use ForeignKey to let it work. How can I use django model to achieve this?
You can do like this :
Tsinger.objects.all().order_by('ftbl_user_profile__fansnum')
For information about Django JOIN :
https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_one/

Categories