Hi Everyone,
I have two legacy models as follows (what legacy models for my case meaning that the underlying tables had been created before the mapping django model created and I only have read permission to the tables):
class Customer(models.ClickhouseModel):
memberid = models.Int64Field(db_column='MemberId', primary_key=True)
activememberid = models.Int64Field(db_column='ActiveMemberId')
class Meta:
managed=False
db_table='Customer'
class Sale(models.ClickhouseModel):
tranid = models.Int64Field(db_column='TranId', null=False, blank=True, primary_key=True)
memberid=models.Int64Field(db_column='MemberId', null=True, blank=True)
class Meta:
managed=False
db_table='Sale'
Given Sale.memberid is the foreign key of Customer.memberid, is it possible to set relationship e.g. one to one relationship from these two legacy models, so that I can retrieve ActiveMemberId when querying sale model table?
select
a.TranId
,a.MemberId
,b.ActiveMemberId <---- retrieve ActiveMemberId when querying sale table
from Sale as a
left join Customer as b
on a.MemberId = b.MemberId
Thank you in advance
Kelvin
why don’t use foreign key??
class Sale(models.ClickhouseModel):
member=models.ForeignKey(Customer, db_column='MemberId', null=True, blank=True)
a = Customer.objects.filter({some value})
Sale.obejcts.filter(member_id__in=a.value_list('memberid', Flat=True))
can we use ForeignKey() for legacy models?
foreign key save model pk value in database.
if you use in memberid that customer pk, just change memberid field int64field to foreign key.
maybe it works.
It depends upon whether the field is an actual foreign key, and whether you are using these models as “read-only” reference data or actively updating them.
If you created these models using inspectdb
, then be aware that inspectdb
is a starting point, not the end point. The inspectdb
command doesn’t identify everything that may apply to those models.
From the docs at Auto-generate the models:
This feature is meant as a shortcut, not as definitive model generation.
This means that Django is expecting you to change these definitions as needed. It’s only going to get you 90% of the way there, it’s up to you to finish tuning those models.
Hi Ken,
I have modified Sale model and replaced memberid field with OneToOneField().
But an error occurred when I made the following query.
Sale.objects.filter(customer__activememberid=999)
The error message shows that Customer does not existed in DatabaseB. The reason is that multiple databases are used in my Django project. Customer is belonged to DatabaseA, whereas Sale is belonged to DatabaseB, and a dbrouter.py with a Router class is used to control the routering.
Given the settings above, do you know how to design the routering function db_for_read(model , **hints ) ?Apparently, I already tried and set the following condition in db_for_read() but it does not work.
if model==Customer:
return DatabaseA
Thank you for your insight in advance.
Kelvin
Quoting directly from the docs for Cross-database-relations:
Django doesn’t currently provide any support for foreign key or many-to-many relationships spanning multiple databases. If you have used a router to partition models to different databases, any foreign key and many-to-many relationships defined by those models must be internal to a single database.
1 Like
Oh my…that means there is nothing I can do about it except repeatedly using CTE to get my activememberid back
Anyway, thank you for your clarification.
Kelvin
I sort of found a solution to get this relationship limitation resolved. Actually, I can create two views for Sale and Customer tables respectively into one database first, then instead of mapping the tables, we can build the relational mapping with the views instead . Hopefully this will work.
Kelvin
in your case, try this…
pk_customer = Customer.objects.get().pk
seles = Sale.objects.filter(memberid__in=pk_customer)
1 Like
I made it and this solution worked.