Django join different tables - django

This is what i got in the models
class SFE(models.Model):
snpid = models.ForeignKey(Snps, models.DO_NOTHING, db_column='SNPID', primary_key=True) # Field name made lowercase.
elementid = models.ForeignKey(Functionalelement, models.DO_NOTHING, db_column='ElementID') # Field name made lowercase.
celllineid = models.ForeignKey(Celllines, models.DO_NOTHING, db_column='CELLLINEID') # Field name made lowercase.
countexperiments = models.PositiveIntegerField(db_column='countExperiments') # Field name made lowercase.
filetype = models.CharField(db_column='fileType', max_length=10) # Field name made lowercase.
class Meta:
managed = False
db_table = 'SNPs_FunctionalElement'
unique_together = (('snpid', 'elementid', 'celllineid', 'filetype'),)
def __str__(self):
return str(str(self.snpid) + str(self.elementid) + str(self.celllineid) + str(self.filetype))
class Functionalelement(models.Model):
elementid = models.AutoField(db_column='ElementID', primary_key=True) # Field name made lowercase.
name = models.CharField(unique=True, max_length=55)
class Meta:
managed = False
db_table = 'FunctionalElement'
def __str__(self):
return str(self.elementid)
class Snps(models.Model):
snpid = models.AutoField(db_column='SNPID', primary_key=True) # Field name made lowercase.
rsid = models.CharField(unique=True, max_length=20)
chrom = models.CharField(max_length=5)
pos = models.PositiveIntegerField()
ref = models.CharField(max_length=1)
alt = models.CharField(max_length=1)
maf1000genomes = models.FloatField(blank=True, null=True)
maftopmed = models.FloatField(db_column='mafTOPMed', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'SNPs'
def __str__(self):
return str(self.snpid)
Now i want to join FunctionalElement with SFE in order to retrieve the field FunctionalElement.name given a specific SFE.snpid.
I tried with SFE.objects.select_related('elementid__name') but i know it's wrong and i can't understand how to work with django ORM

To get a simple object you need to do: a = SFE.objects.get(snpid=THE_SPECIFICSNPID) later you can access to all the related objects, for example: a.elementid.name will return what you want.
The Django ORM take retrieve the object for you, that is because "lazzy loading". That means that if you need a related object later Django will get it for you, of course, it need to do another query and to avoid that you need to call the method select_related
Summarizing:
To get the name you can do:
name = SFE.objects.get(snpid=THE_SPECIFICSNPID).select_related('elementid').elementid.name
It should works

Related

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 - Legacy database tables - Querying 2 one to many tables

I am new to Django and would like some advice on how to query from 3 tables.
I have 3 tables from legacy database mapped in to models (Patient, PrescribedMeds, PrescribedMedsSchedule). We can't change this structure since this will have to remain active while we create the Django application.
1 patient can have many prescribed medication.
1 prescribed medication can have several times in the schedule
Below is the model in django.
models.py
class Patient(models.Model):
patient_name = models.CharField(db_column='patient_name', max_length=50)
dob = models.DateTimeField(db_column='DOB', blank=True, null=True) # Field name made lowercase.
gender = models.CharField(db_column='Gender', max_length=7) # Field name made lowercase.
dateofentry = models.DateTimeField(db_column='DateOfEntry', blank=True, null=True) # Field name made lowercase.
....
....
class Meta:
managed = False
db_table = 'patient'
def __str__(self):
return self.patient_name
class PrescribedMeds(models.Model):
#id = models.AutoField(db_column='ID', primary_key=True) # Field name made lowercase.
patient_id= models.ForeignKey(Patient, models.DO_NOTHING, db_column='patient_id')
med_type = models.SmallIntegerField(db_column='Type') # Field name made lowercase.
name_of_medication = models.CharField(db_column='Name_Of_Medication', max_length=50, blank=True, null=True) # Field name made lowercase.
rxno = models.CharField(db_column='RxNo', max_length=50, blank=True, null=True) # Field name made lowercase.
date_filled = models.DateTimeField(db_column='DateFilled', blank=True, null=True) # Field name made lowercase.
....
....
class Meta:
managed = False
db_table = 'prescribed_meds'
def __str__(self):
return str(self.id) + ", " + self.name_of_medication + ", " + str(self.childno)
class PrescribedMedsSchedule(models.Model):
#id = models.AutoField(db_column='ID', primary_key=True) # Field name made lowercase.
prescribed_meds_id = models.ForeignKey(PrescribedMeds, models.DO_NOTHING, db_column='prescribed_meds_ID') # Field name made lowercase.
medication_date = models.DateField()
medication_time = models.DateTimeField()
quantity = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
form = models.CharField(max_length=1, blank=True, null=True)
class Meta:
managed = False
db_table = 'prescribed_meds_schedule'
I am trying to get the right syntax in Django to display data from the 3 columns (Prescribed_Meds.ID, PrescribedMeds.name_of_medication, Patient.patient_name, PrescribedMedsSchedule.medication_date, PrescribedMedsSchedule.medication_time).
In SQL the query would be
SELECT prescribed_meds.ID, prescribed_meds.Name_Of_Medication, patient.patient_name, prescribed_meds_schedule.medication_date, prescribed_meds_schedule.medication_time
FROM prescribed_meds_schedule
INNER JOIN (prescribed_meds INNER JOIN patient ON prescribed_meds.patient_id = patient.id) ON prescribed_meds_schedule.prescribed_meds_ID = prescribed_meds.ID;
What would be the correct query in Django? I am having an issue since there is no relationship from PrescribedMedsSchedule to Patient table.
I have tried the following:
my_obj = PrescribedMedsSchedule.objects.all().selected_related(
'prescribed_meds_id'
).prefetch_related('PrescribedMeds__patient_id')
However, this query does not bring up the Patient table/model.
Any advice would be appreciated.
It's worth starting with a note on what django does internally with a FK. You have a suffix in your models of _id but django will do this to the database column automatically. So in your model you could have an easier to read field, patient = models.ForeignKey(Patient) and it will be patient_id in the database.
select_related follows foreign-key relationships, so you're right to do that. If you want to INNER join you should follow the foreign-keys. In your case use the
double-underscore to get through the models:
PrescribedMedsSchedule.objects.all().select_related(
'prescribed_meds_id'
).select_related('prescribed_meds_id__patient_id')
Or you could use 2 queries and use the id values from PrescribedMeds to then query PrescribedMedsSchedule. That would be something like;
meds = PrescribedMeds.objects.all().select_related('patient_id')
med_ids = meds.values_list('id', flat=True)
schedules = PrescribedMedsSchedule.objects.filter(prescribed_meds_id__in=med_ids)

Django Join on Composite foreign key

I have a relationship as Follows
class Tblrfqvendor(models.Model):
"""RFQ Master for Vendors
This typical represents the same RFQ sent to different people
"""
ven_rfqid = models.ForeignKey(Tblrfqitem, db_column='RFQID', on_delete=models.DO_NOTHING, primary_key=True,related_name="venrfq") # Field name made lowercase.
lineitem = models.IntegerField(db_column='LineItem') # Field name made lowercase.
vendorid = models.CharField(db_column='VendorID', max_length=10) # Field name made lowercase.
class Meta:
managed = False
db_table = 'tblRFQVendor'
constraints = [constraints.UniqueConstraint(fields=['ven_rfqid', 'lineitem', 'vendorid'], name='unique_vendor_rfq')]
ordering = ['-lastrevdate']
class Tblrfqitem(models.Model):
"""A Line Item for a particular Master Vendor RFQ
"""
item_rfqid = models.ForeignKey(Tblrfqmaster, db_column='RFQID', on_delete=models.DO_NOTHING, primary_key=True,related_name='items') # Field name made lowercase.
lineitem = models.IntegerField(db_column='LineItem')
itemid = models.CharField(db_column='ItemID', max_length=100, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'tblRFQItem'
constraints = [constraints.UniqueConstraint(fields=['item_rfqid','lineitem'], name='unique_item')]
How can I get it so that I can serialize on both lineitem and ven_rfid instead of just the single primary key?

I am working with Django, During inserting data into database i caught such error

I'm working with django, during inserting data into tables the error is generates as given below...
Error:
int() argument must be a string, a bytes-like object or a number, not 'Tbl_rule_category', How can we solve such error?
view.py
dataToRuleCtgry = Tbl_rule_category(category=category, created_by="XYZ",created_date=datetime.date.today())
dataToRuleCtgry.save()
dataToRule = Tbl_rule(rule_name=rule_name, closure=closure,category_id=Tbl_rule_category.objects.latest('category_id'), created_by="XYZ",created_date=datetime.date.today(), updated_by="XYZ", updated_date=datetime.date.today(), rule_type=rule_type, fk_tbl_rule_tbl_rule_category_id=Tbl_rule_category.objects.latest('category_id'))
dataToRule.save()
models.py
class Tbl_rule_category(models.Model):
category_id = models.AutoField(primary_key=True)
category = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
def __str__(self):
pass # return self.category, self.created_by
class Tbl_rule(models.Model):
rule_id = models.AutoField(primary_key=True)
rule_name = models.CharField(max_length=50)
closure = models.CharField(max_length=50)
category_id = models.IntegerField()
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
updated_by = models.CharField(max_length=50)
updated_date = models.DateField(auto_now=True)
rule_type = models.CharField(max_length=50)
fk_tbl_rule_tbl_rule_category_id = models.ForeignKey(Tbl_rule_category,on_delete=models.CASCADE, related_name='fk_tbl_rule_tbl_rule_category_id_r')
def __str__(self):
return self.rule_name, self.closure, self.created_by, self.updated_by, self.rule_type
The error is occurring because the following is trying to add an object into an integer field: category_id=Tbl_rule_category.objects.latest('category_id')
You could just add: category_id=dataToRuleCtgry.get('category_id') or category_id=dataToRuleCtgry.category_id which will solve the error.
You also don't need to add: created_date=datetime.date.today() because your model defines auto_now=true.
As mentioned you should also amend the def __str__(self): to return a string.
https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model.str
Alternatively
You could just add the object link directly to your foreign key for the category model.fk_tbl_rule_tbl_rule_category_id=dataToRuleCtgry. You would no longer need the integer field category_id.
It would be better practice to use the model field name category_id instead of fk_tbl_rule_tbl_rule_category_id. This would mean deleting category_id and then rename fk_tbl_rule_tbl_rule_category_id to category_id.
In Django, the ORM takes care of the basic database details for you; which means in your code you really don't have to worry about individual row ids for maintaining foreign key relationships.
In fact, Django automatically assigns primary keys to all your objects so you should concentrate on fields that are relevant to your application.
You also don't have to worry about naming fields in the database, again Django will take care of that for you - you should create objects that have fields that are meaningful to users (that includes you as a programmer of the system) and not designed for databases.
Each Django model class represents a object in your system. So you should name the classes as you would name the objects. User and not tbl_user. The best practice is to use singular names. Django already knows how to create plural names, so if you create a model class User, django will automatically display Users wherever it makes sense. You can, of course, customize this behavior.
Here is how you should create your models (we will define __str__ later):
class RuleCategory(models.Model):
name = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
class Rule(models.Model):
name = models.CharField(max_length=50)
closure = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
updated_by = models.CharField(max_length=50)
updated_date = models.DateField(auto_now=True)
rule_type = models.CharField(max_length=50)
category = models.ForeignKey(RuleCategory,on_delete=models.CASCADE)
Django will automatically create any primary or foreign key fields, and any intermediary tables required to manage the relationship between the two models.
Now, to add some records:
new_category = RuleCategory(name='My Category', created_by='XYZ')
new_category.save()
# Another way to set values
new_rule = Rule()
new_rule.name = 'Sample Rule'
new_rule.closure = closure
new_rule.created_by = 'XYZ'
new_rule.updated_by = 'XYZ'
new_rule.rule_type = rule_type
new_rule.category = new_category
new_rule.save()
Note this line new_rule.category = new_category - this is how we link two objects. Django knows that the primary key should go in the table and will take care of that automatically.
The final item is customizing the models by creating your own __str__ method - this should return some meaningful string that is meant for humans.
class RuleCategory(models.Model):
name = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
def __str__(self):
return '{}'.format(self.name)
class Rule(models.Model):
name = models.CharField(max_length=50)
closure = models.CharField(max_length=50)
created_by = models.CharField(max_length=50)
created_date = models.DateField(auto_now_add=True)
updated_by = models.CharField(max_length=50)
updated_date = models.DateField(auto_now=True)
rule_type = models.CharField(max_length=50)
category = models.ForeignKey(RuleCategory,on_delete=models.CASCADE)
def __str__(self):
return '{} for category {}'.format(self.name, self.category)
If you notice something, I just put self.category in the __str__ for the Rule model. This is because we have already defined a __str__ for the RuleCategory model, which just returns the category name; so now when we print our Rule we created, we will get Sample Rule for category My Category as a result.

django model instance could not get the field after save

Here is my code:
models.py
class TblUser(models.Model):
uid = models.IntegerField(primary_key=True, db_column='ID') # Field name made lowercase.
username = models.CharField(max_length=3072, db_column='UserName', blank=True) # Field name made lowercase.
password = models.CharField(max_length=3072, db_column='PassWord', blank=True) # Field name made lowercase.
datesstart = models.DateTimeField(null=True, db_column='datesStart', blank=True) # Field name made lowercase.
datesend = models.DateTimeField(null=True, db_column='datesEnd', blank=True) # Field name made lowercase.
num = models.IntegerField(null=True, db_column='Num', blank=True) # Field name made lowercase.
power = models.IntegerField(null=True, db_column='Power', blank=True) # Field name made lowercase.
email = models.CharField(max_length=12288, blank=True)
class Meta:
db_table = u'tbl_user'
def __unicode__(self):
return '%d--%s--%d'%(self.uid,self.username,self.power)
views.py
from app.models import TblUser
def appendUser(self,name,pwd):
#I add a new user,and the primary_key:uid is autoincrement in datebase
user = TblUser.objects.create(username=name,password=pwd)
print user.uid#None
When I call the appendUser(),it will insert a new record into datebase, and the user(TblUser's instance) only have two valid fields(username,password), the other is empty.
How can I get the user.uid because I want handle other things by using it?
You should use an AutoField not an IntegerField for the pk: https://docs.djangoproject.com/en/1.4/ref/models/fields/#autofield
You might want to read this post, different approach using ModelForm:
Get Primary Key after Saving a ModelForm in Django