I am new in django framework.I have 3 tables in mysql database. I want to fetch data from main table with translation table and images table.
My model.py
class Country(models.Model):
#id = models.IntegerField(primary_key=True)
iso_code = models.CharField(max_length=2, unique=True)
slug = models.CharField(max_length=255, unique=True)
is_featured = models.IntegerField(max_length=1)
class Meta:
db_table = 'rh_countries'
class CountryTranslation(models.Model):
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
locale = models.CharField(max_length=2)
class Meta:
db_table = 'rh_countries_translations'
class CountryImage(models.Model):
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
image = models.CharField(max_length=255)
is_main = models.IntegerField(max_length=1)
class Meta:
db_table = 'rh_country_images'
Now I want to fetch all country with translation record by locale and associated image.
Please give a solution if anyone know.
You can do this by using a filtering, and annotate:
from django.db.models import F
Country.objects.filter(
countrytranslation__locale=mylocale
).annotate(
name=F('countrytranslation__name')
)
This will result in a QuerySet with all Countrys (that have a Translation for the given mylocale). These Countrys will have an extra attribute .name that is the translated name of the Country.
So given the translations exist, then for mylocale='en', this will result in a QuerySet, with Country(name='Germany', iso_code='de'), and for mylocale='de', it will result in Country(name='Deutschland', iso_code='de') (here this is a bit an ad hoc format, to demonstrate how it works).
Note: ForeignKeys typically do not end with _id. Django will automatically add an _id suffix to the database column. The foreign key itself is on the Python/Django level represented as a lazy loaded attribute.
Related
I have 3 django tables connected like this:
Is there anyway to make a query for table Table that will get id_equip from table equip?
models.py
class Vendor(models.Model):
vendor_name = models.CharField(max_length=50)
def __str__(self):
return self.vendor_name
class Equipment(models.Model):
equipment_name = models.CharField(max_length=50)
id_vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
def __str__(self):
return self.equipment_name
class Table(models.Model):
table_name = models.CharField(max_length=100)
id_vend = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
id_equip = models.ManyToManyField(Equipment)
This part of the django docs is relevant and helpful, I definitely recommend your review at least that section and ideally the whole page.
Your models are already denormalized as evidenced by Table.id_equip which relates to Equipment so you could do:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(table.id_equip.all().values_list('id', flat=True))
If you wanted to go through the vendor I'd suggest:
table = Table.objects.get(SOME_FILTER)
equipment_ids = list(Equipment.objects.filter(vendor_set__table_set=table).values_list('id', flat=True))
I would recommend that you don't name your relationship fields with id_. With an ORM, these fields should represent the instances of the Model they are mapping to. For example:
class Table(models.Model):
name = models.CharField(max_length=100)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None)
equipment = models.ManyToManyField(Equipment)
If you're trying to create the model on top of an existing table, you can make use of the db_column parameter when defining the field.
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, db_column="id_vend")
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
I want to set a foreign key to a field of another model.
I have tried Foreign Key to_field='field_name'
class Banks(models.Model):
name = models.TextField()
id = models.IntegerField(unique=True)
class Meta:
db_table = 'banks'
class Branches(models.Model):
ifsc = models.CharField(max_length=20, null=False)
bank_id = models.ForeignKey(Banks, to_field='id', on_delete=models.CASCADE)
branch = models.CharField(max_length=50)```
ProgrammingError: column branches.id does not exist
LINE 1: SELECT "branches"."id", "branches"."ifsc", "branches"."bank_...
Just add unique=True in the name column, in the Banks model.
class Banks(models.Model):
name = models.TextField(unique=True) # Just add unique=True
id = models.IntegerField(unique=True, primary_key=True)
class Meta:
db_table = 'banks'
class Branches(models.Model):
ifsc = models.CharField(max_length=20, null=False)
bank_id = models.ForeignKey(Banks, to_field='id', on_delete=models.CASCADE) # Now it will work
branch = models.CharField(max_length=50)
This problem is not caused by the foreign key. The error is happening in the Branches model, which presumably also has a db_table Meta attribute and is based on a legacy table.
You must define a primary key for your models. If you don't, Django will do so automatically and call it id. In the case of your Banks model, you should set that id field as primary_key=True - or indeed remove it completely, since that is the default. You need to find a suitable pk for Branches as well and declare it in the field.
For your actual question, you don't need to do anything; Django will automatically set the FK to point to the PK of the target model.
class Bank(models.Model):
# removed `id` as that is the default PK
name = models.TextField()
class Meta:
db_table = 'banks'
class Branch(models.Model):
ifsc = models.CharField(max_length=20, primary_key=True) # assume this is the PK
bank = models.ForeignKey(Bank, on_delete=models.CASCADE)
branch = models.CharField(max_length=50)
class Meta:
db_table = 'branches'
Note also, since these are legacy tables you probably want to add managed = False to both Meta classes. And as suggested by AKX, it is Django style to make model names singular; you can do that without affecting the table name since that is declared explicitly.
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.
I'm interacting with a legacy db on another system, so the models are written in stone and not very django-ey.
My models.py:
class Site(models.Model):
site_code = models.CharField(max_length=30, primary_key=True)
name = models.CharField(unique=True, max_length=300)
class Document(models.Model):
id = models.IntegerField(primary_key=True)
site_ref = models.ForeignKey(Site)
description = models.CharField(max_length=1500)
class DocumentStatusCategory(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=90)
class DocumentStatus(models.Model):
id = models.IntegerField(primary_key=True)
document = models.ForeignKey(Document)
status = models.ForeignKey(DocumentStatusCategory)
changed_by = models.ForeignKey(User)
created_at = models.DateTimeField()
In my views.py I want to retrieve a queryset with all the Document objects that belong to a specified Site (say site_ref=mysite) which do not have any related DocumentStatus objects with status=4.
Any idea how I can do this as a single (non-sql intensive) line?
Document.objects.filter(site_ref=mysite).exclude(documentstatus__status_id=4)
Document.objects.filter(site_ref=site_obj).exclude(documentstatus_set__in=DocumentStatus.objects.filter(status_id=4))
Not exactly one query, but I don't think that's achievable without going down to raw sql. Two queries isn't bad though I suppose.
I should mention that the above assumes that the reverse relation between Document and DocumentStatus is documentstatus_set. You can explicitly state what the reverse relation is like so:
# inside the DocumentStatus model definition
document = models.ForeignKey(Document, related_name='document_statuses')
Then the query becomes:
Document.objects.filter(site_ref=site_obj).exclude(document_statuses__in=DocumentStatus.objects.filter(status_id=4))