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
Related
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 have a Django model for a player of a game
class Player(models.Model):
name = models.CharField(max_length=50)
team = models.ForeignKey('Team', on_delete=models.CASCADE, blank=True, null=True)
game = models.ForeignKey('Game', on_delete=models.CASCADE)
objects = GameManager()
class Meta:
unique_together = ('name', 'game',)
I have only one unique constraint, that the name and the game are unique together.
Now, I would like to extend our page by adding registered users. So, I would add this to the model.
user = models.ForeignKey('auth.User', on_delete=models.CASCADE, blank=True, null=True)
So, an registered user can subscribe to a game by adding a name, team, game, and his/her user. However, the user should only be able to add his account once to an game, which would be a second unique constrain
unique_together = ('user', 'game',)
Is it possible to give in Django two unique constraints to the model? Or do I have to search in the table manually prior to saving the new entries? Or is there a better way?
Yes, in fact by default unique_together is a collection of collections of fields that are unique together, so something like:
class Player(models.Model):
name = models.CharField(max_length=50)
team = models.ForeignKey('Team', on_delete=models.CASCADE, blank=True, null=True)
game = models.ForeignKey('Game', on_delete=models.CASCADE)
objects = GameManager()
class Meta:
unique_together = (('name', 'game',), ('user', 'game',))
Here we thus specify that every name, game pair is unique, and every user, game pair is unique. So it is impossible to create two Player objects for the same user and game, or for the same game and name.
It is only because a single unique_together constraint is quite common, that one can also pass a single collection of field names that should be unique together, as is written in the documentation on Options.unique_together [Django-doc]:
Sets of field names that, taken together, must be unique:
unique_together = (("driver", "restaurant"),)
This is a tuple of tuples that must be unique when considered
together. It's used in the Django admin and is enforced at the
database level (i.e., the appropriate UNIQUE statements are included
in the CREATE TABLE statement).
For convenience, unique_together can be a single tuple when dealing with a single set of fields:
unique_together = ("driver", "restaurant")
You should use models.UniqueConstraint (reference).
As noted in the reference:
UniqueConstraint provides more functionality than unique_together. unique_together may be deprecated in the future.
Do this:
class Meta:
constraints = [
models.UniqueConstraint(fields=['name', 'game'], name="unique_name_game"),
models.UniqueConstraint(fields=['user', 'game'], name="unique_user_game"),
]
For example please refer to this :-
class Stores(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=50)
lat = models.FloatField()
lng = models.FloatField()
merchant = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="stores")
def __str__(self):
return "{}: {}".format(self.name, self.address)
class Meta:
verbose_name_plural = 'Stores'
class Items(models.Model):
name = models.CharField(max_length=50, unique=False)
price = models.IntegerField()
description = models.TextField()
stores = models.ForeignKey(Stores, on_delete=models.CASCADE, related_name="items")
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Items"
unique_together = ('name', 'stores',)
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.
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 have two tables RoomPriceDetails and HotelDetails. RoomPriceDetails has a foreign key which I want to point to the primary key field named hotel_id of HotelDetails. I used to_field attribute for this, but it seems I am going wrong some where. It shows me error like
ValueError: invalid literal for int() with base 10: 'BMH-1'.
when I try to add the hotel_id 'BMH-1' in RoomPriceDetails. 'BMH-1'is a hotel id in HotelDetails. If I am wrong what is the best way to make my foreign key to point to my hotel_id field in HotelDetails to accept those values.
My models:
class RoomPriceDetails(models.Model):
room_type = models.CharField(max_length=255, primary_key=True)
hotel = models.ForeignKey(HotelDetails, to_field='hotel_id')
price_per_day = models.PositiveIntegerField(default=0)
class HotelDetails(models.Model):
hotel_id = models.AutoField(primary_key=True, db_column='hotel_id')
name = models.CharField(max_length=255)
email = models.CharField(max_length=255)
reg_no = models.CharField(max_length=255)
contact_no = models.CharField(max_length=10)
owner_name = models.CharField(max_length=255)
owner_email = models.CharField(max_length=255)
owner_contact_no = models.CharField(max_length=255)
address = models.CharField(max_length=400)
city = models.CharField(max_length=255)
state = models.CharField(max_length=255)
pincode = models.CharField(max_length=6)
Autofield can only hold an integer, by default Django sets auto field.
An IntegerField that automatically increments according to available IDs. You usually won’t need to use this directly; a primary key field will automatically be added to your model if you don’t specify otherwise.
What you would like is add primary_key to your CharField
Field.primary_key
If True, this field is the primary key for the model.
In your example:
class HotelDetails(models.Model):
hotel_id = models.CharField(primary_key=True, db_column='hotel_id', max_length=10)
Having primary key not being integer can decrease your DB performance