Django Model - JOIN Tables without adding models - django

I have two databases to connect to for my Django App. I have only read access for one of the database, from where I want to pull only a few columns for my model into the other database where I have read and write access. It does not make sense to 'inspectdb' the read access databases with 100+ tables and the 100+ columns for just a few columns.
How do I add the column from another database to my existing model in the simplest manner using a join? Can I use a raw sql query with parameters to add the field into my model?
class APPNAME(models.Model):
class Meta:
db_table = 'APPNAME'
item= models.PositiveIntegerField(db_column='Item')
issue = models.CharField(max_length=200, db_column='Issue')
detail = models.TextField(db_column='Detail')
created_at = models.DateTimeField(auto_now_add=True, db_column='Create Datetime')
updated_at = models.DateTimeField(auto_now=True, db_column='Update Datetime')
external_column = How to join this column???
Here is a simple SQL Query to showcase what I am trying to do with the Django model.
SELECT
APP.[Item]
,APP.[Issue]
,APP.[Detail]
,APP.[Create Datetime]
,APP.[Update Datetime]
,BIG.[External Column]
FROM DEVDB.dbo.APPNAME APP
INNER JOIN PRODDB.dbo.BIGTABLE BIG ON APP.[Item] = BIG.[Item]

Related

Use model.save data for Meta Tag in Django

Thank you for reading i am new to Django and
For my application it's a requirement to create a table for each client to store his data.
Each client table has the same data so i made a Model for it.
But the table name is variable:
i tried
Models.py
class Meta:
abstract = True
organisation = models.CharField(max_length=255, null=True, blank=True,)```
Model
```class Test(DatIm):
class Meta(DataIm.Meta):
db_table = DatIm.organisation```
in the view:
```Test.objects.update_or_create(organisation=row['organisation'])```
but it doesnt create the table and gives errors.
i would expect to
creates or get the table for organisation
insert model.save data in organisation Db
I need for each organisation an table because a lot of data.

Django with legacy database - how to work with DB sequences?

Given a database table that was created using this SQL query:
CREATE TABLE Bill
(
Time DATE NOT NULL ,
Address VARCHAR2 (60) NOT NULL ,
ID NUMBER NOT NULL
) ;
ALTER TABLE Bill ADD CONSTRAINT Bill_PK PRIMARY KEY ( ID ) ;
CREATE SEQUENCE Bill_ID_SEQ START WITH 1 NOCACHE ORDER ;
CREATE OR REPLACE TRIGGER Bill_ID_TRG BEFORE
INSERT ON Paragony FOR EACH ROW BEGIN :NEW.ID := Bill_ID_SEQ.NEXTVAL;
END;
I have to use it with Django ORM so I have run inspectdb command. It is the autogenerated code:
class Bill(models.Model):
time = models.DateField()
address = models.CharField(max_length=60)
id = models.IntegerField(primary_key=True)
class Meta:
managed = False
db_table = 'bill'
After saving it to app' models.py file and running migrations everything was fine. I could read DB like it was created using ORM. However there was a problem with creating rows in Bill table.
It is simple form for Bill model:
class BillForm(ModelForm):
class Meta:
model = Bill
fields = ('time', 'address')
The problem is that I can't retrieve the ID generated with the DB sequence. Adding id field to Form won't work because we have to generate it with code and then pass as a argument. Even than database will create different ID that will not be possible to retrieve without raw queries.
The solution is really simple. We have to remove the id field from Bill model:
class Bill(models.Model):
time = models.DateField()
address = models.CharField(max_length=60)
# Remove 'id' field so the ORM can work properly.
# id = models.IntegerField(primary_key=True)
class Meta:
managed = False
db_table = 'bill'
This way the Django ORM can make all the hard work and correctly use legacy database sequences. Bill objects now can be created using BillForm and they will have proper IDs.

Combine the information of two tables into a single Django model

I need to read data for an external database (I cannot modify the table structure) with the two following tables:
Table1
Key (primary key)
Field1
Table2
Key (primary key)
Field2
Is it possible to combine these two tables into a single Django Model that looks like:
Model:
Key (primary key)
Field1
Field2
Additional information:
The keys of the entries in Table2 are a subset of the entries in Table1. So for any entry in Table2 there is a matching entry in Table1, but not viceversa
Work so far:
I have a one model for each table (1 and 2) and Table1 model has a "field2" #property that looks up the corresponding information in the Table2 model.
Also, I can do this at the sql level with the following query:
SELECT
table1.key,
table1.field1,
table2.field2,
FROM
table1
LEFT OUTER JOIN table2
ON table1.key=table2.key
ORDER BY table1.key ASC
===
Solution implementation details update after seeing some of the answers:
From Daniel Roseman's answer
I ended up with two models:
class Model1(models.Model):
key = models.CharField(max_length=100, primary_key=True)
field1 = models.TextField()
class Meta:
managed = False
db_table = 'Table1'
def field2_value(self):
try:
return self.field2.value
except Model2.DoesNotExist:
return None
class Model2(models.Model):
key = models.OneToOneField(Model1, primary_key=True, db_column='key',
related_name='field2')
field2 = models.TextField()
class Meta:
managed = False
db_table = 'Table2'
While it is not exactly what I had originally in mind when I asked this question, it meets my desired use case
Also, here are the corresponding admin classes:
class Model2Admin(admin.StackedInline):
model = Model2
#admin.register(Model1)
class Model1Admin(admin.ModelAdmin):
inlines = (Model2Admin,)
list_display = ('key', 'field1', 'field2_value')
# Loads the related property in one SQL call instead of one call per entry
list_select_related = ('field2',)
Thanks KaaN SARIKAYA for your great answer. I didn't know that I could create a view of the two tables. If I could modify the database structure I would opt for your option.
A better solution would be to keep these as two models, but have the primary key of the second be a OneToOneField to the first.
You cannot merge the model because they are 2 physical tables, django models are tied by the database table names so you couldn't do what you want. If you have the control for those external database tables and have the right to modify them, you should modify the schema first and merge the data. If you don't want to or you cannot modify anything, your current way is OK.
You can create a table_view on sql and make an abstract model on django . Suppose you have 2 pyhsical models and tables.
SQL CODE:
CREATE OR REPLACE VIEW combine_two_model_view AS
SELECT
mt1.name as mt1_name,
mt2.name as mt2_name,
mt1.pub_date as mt1_pub_date
.
.
.
.
FROM modeltable1 mt1
LEFT JOIN modeltable2 mt2 ON mt2.id = mt1.id
ALTER TABLE combine_two_model_view
OWNER TO dbuser;
we created sql view table. now, we will create an abstract model
in your models.py:
class YourModelsCombine(models.Model):
class Meta:
abstract = True
db_table = "combine_two_model_view"
mt1_name = models.CharField(max_length=100)
mt2_name = models.TextField(max_length=2000)
mt1_pub_date = models.DateTimeField("Publish Date", auto_now_add=True)
mt2_pub_date = models.DateField("Updated Date", auto_now=True)
mt1_integer = models.IntegerField(default=0)
#etc
attention: make sure your table view variable names and model variable names must be same. Finally;
in your admin.py:
admin.site.register(YourModelsCombine)
You will see combine of two tables on your django-admin
I hope this helps to you

Basic relations in django (built on top of a legacy db)

I've googled on and on, and I just don't seem to get it.
How do I recreate simple join queries in django?
in models.py (Fylker is county, Dagensrepresentanter is persons)
class Fylker(models.Model):
id = models.CharField(max_length=6, primary_key=True)
navn = models.CharField(max_length=300)
def __unicode__(self):
return self.navn
class Meta:
db_table = u'fylker'
class Dagensrepresentanter(models.Model):
id = models.CharField(max_length=33, primary_key=True)
etternavn = models.CharField(max_length=300, blank=True)
fornavn = models.CharField(max_length=300, blank=True)
fylke = models.ForeignKey(Fylker, db_column='id')
def __unicode__(self):
return u'%s %s' % (self.fornavn, self.etternavn)
class Meta:
ordering = ['etternavn'] # sette default ordering
db_table = u'dagensrepresentanter'
Since the models are auto-created by django, I have added the ForeignKey and tried to connect it to the county. The id fields are inherited from the db I'm trying to integrate into this django project.
By querying
Dagensrepresentanter.objects.all()
I get all the people, but without their county.
By querying
Dagensrepresentanter.objects.all().select_related()
I get a join on Dagensrepresentanter.id and Fylker.id, but I want thet join to be on fylke, aka
SELECT * FROM dagensrepresentanter d , fylker f WHERE d.fylke = f.id
This way I'd get the county name (Fylke navn) in the same resultset as all the persons.
Additional request:
I've read over the django docs and quite a few questions here at stackoverflow, but I can't seem to get my head around this ORM thing. It's the queries that hurt. Do you have any good resources (blogposts with experiences/explanations, etc.) for people accustomed to think of databases as an SQL-thing, that needs to start thinking in django ORM terms?
Your legacy database may not have foreign key constraints (for example, if it is using MyISAM then foreign keys aren't even supported).
You have two choices:
Add foreign key constraints to your tables (would involve upgrading to Innodb if you are on MyISAM). Then run ./manage inspectdb again and the relationships should appear.
Use the tables as is (i.e., with no explicit relationships between them) and compose queries manually (e.g., Mytable.objects.get(other_table_id=23)) either at the object level or through writing your own SQL queries. Either way, you lose much of the benefit of python's ORM query language.

Better way to query this Django Model

I am new to Django. I have a model and now I need to query the model.
The model is this:
from django.db import models
import datetime
class Position(models.Model):
website_position = models.IntegerField()
category = models.ForeignKey('Category')
directorio = models.ForeignKey('Directorio')
class Category(models.Model):
n_category = models.CharField(max_length=100)
category_position = models.IntegerField()
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now_add=True)
class Directorio(models.Model):
website_name = models.CharField(max_length=200)
website_url = models.URLField()
activated = models.BooleanField()
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField(Category, through=Position)
Now, I need to query the database in this way:
select dc.n_category, dp.website_position, dd.website_name, dd.website_url, dd.activated
from directorio_category as dc
join directorio_position as dp on dc.id = dp.category_id
join directorio_directorio as dd on dp.directorio_id = dd.id
where dd.activated = 'true'
Question: Should I use the Model Query API or should I use RAW SQL?
Best Regards,
You can do it with the model query api, but if you already have the raw sql written that's going to be more efficient in the long term if you have to scale to enormous heights.
Pro of raw SQL: More efficiently hit the database.
Pro of query api: Non SQL django people will be able to maintian and extend your code in the future.
I've been interacting with databases via django's orm so long that I'm struggling to figure out what your query even means.
#I think this gets what you want
positions = Position.objects.filter(directorio__activated=True).order_by('category__n_catgory', 'website_position')
for position in positions:
print position.category.n_category, position.website_position, position.directorio.website_name, position.website.website_url, position.website.activated
The key to migrating from SQL to django's ORM is starting to think in terms of the primary object(s) you want, then walking the relationships to get the related data. All data related to an object is available to you via object/dot notation, and thanks to the django ORM's laziness, most of it isn't retrieved until you ask for it.
The above code gets every position by category, then walks the relationships to get the other data. Another version of the code might get every active website then show its categories and positions:
websites = Directorio.objects.filter(activated=True).order_by('website_name')
for website in websites:
print website.website_name, website.website_url, website.activated
for position in website.position_set.all().order_by('category__n_category'):
print " -- ", position.category.n_category, position.website_position