Does foreign key have to be primary key in Django? - django

Can we use any other unique column as foreign key in django model?

Yes you can. Column must be unique=True.
To reference this column, specify to_fied attribute on source column. Check below;
class Group (models.Model):
name= models.CharField(max_length=250)
otherid=models.IntegerField(unique=True)
class Member (models.Model):
name=models.CharField(max_length=250)
group=models.ForeignKey(Group,models.CASCADE,to_field='otherid')

Related

How to add foreign key in table using existing column without losing data in django with sqlite3?

I want to alter some tables that have IntegerField type into a foreign key without losing any data. so, How can I do that in both sqlite3 and Django when I do makemigrations command?
this is models looks like:
class Sentences(models.Model):
actor_id = models.IntegerField(blank=True, null=True)
film_id = models.IntegerField(blank=True, null=True)
class Tokens(models.Model):
word_id = models.IntegerField(blank=True, null=True)
sentence_id = models.IntegerField(blank=True, null=True)
class Actors(models.Model):
...
class Words(models.Model):
...
class Films(models.Model):
...
every _id has IntegerField in the first place is referred to the actual id from another table but instead, I want to modify it to become ForeignKey instead of IntegerField how I do that modification?
id is a primary key for every table. It has unique values for each row. Foreign Key is the column that refers to the primary key of another table. To define Foreign Key refer the model name like
class Tokens(models.Model):
word = models.ForeignKey(Words, on_delete=models.CASCADE)
sentence = models.ForeignKey(Sentence, on_delete=models.CASCADE)
..........
After migrating your relation (Table) "Tokens" will have two columns 1. word_id and 2. sentence_id
Refer : https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_one/

How are many-to-many relationship handled in Django?

I have a shirt which can contain multiple colors, and multiple colors which can have multiple shirts. Normally I would express it the following way:
In django I have the many-to-many (https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/)
Example:
publications = models.ManyToManyField(Publication)
--
Can I create the table "Item_colors" consisting of 2 columns (no "ID" primary key) and design the models according to my diagram using the composite key:
class Item_colors(models.Model):
class Meta:
unique_together = (('cloth_item_id', 'color_id'),)
cloth_item_id = models.ForeignKey(Cloth_item, on_delete=models.CASCADE)
color_id = models.ForeignKey(Color, on_delete=models.CASCADE)
How is the many-to-many relation handled in a DB context, and does it yield better performance?
EDIT: https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys no avoiding primary keys in favor of composite keys saving columns :( at least for now..
How is the many-to-many relation handled in a DB context, and does it yield better performance?
With a junction table in the middle, so with an item_colors table. But the table contains a primary key, as does every model in Django.
If you do not specify a through=… parameter [Django-doc] to define the model for the junction table yourself, Django will automatically create such model. This model then has two ForeignKeys to the two models it connects as discussed in the database representation section of the documentation:
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it. Since some databases don’t support table names above a certain length, these table names will be automatically truncated and a uniqueness hash will be used, e.g. author_books_9cdf. You can manually provide the name of the join table using the db_table option.
But the table thus has a primary key. This might be useful if the same object occurs a second time in the relation.
You can access the through model in the Article-Publication example for example with:
Article.publications.through
You thus can define a through model yourself, for example with:
class Color(models.Model):
color = models.CharField(max_length=128)
class ClothItem(models.Model):
item_name = models.CharField(max_length=128)
colors = models.ManyToManyField(
Color,
related_name='cloth_items'
through='ClothItemColors'
)
class ClothItemColors(models.Model):
cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
color = models.ForeignKey(Color, on_delete=models.CASCADE)
class Meta:
db_table = 'item_colors'
constraints = [
models.UniqueConstraint(
fields=('cloth_item', 'color'),
name='unique_cloth_color'
)
]
often an explicit through model is used to store extra information, for example the quantity:
class ClothItemColors(models.Model):
cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
color = models.ForeignKey(Color, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
# …

Trying to make a PostgreSQL field with a list of foreign keys in Django

Here is what I'm trying to do:
Make a model in Django that is a PostgreSQL array (database specific type), which contains foreign keys to another model.
class Books(models.Model):
authors = ArrayField(
models.ForeignKey('my_app.Authors', default=None, null=True, blank=True),
blank=True,
default=list()
)
When I try to makemigrations, Django gives me this error:
SystemCheckError: System check identified some issues:
ERRORS:
my_app.Books.authors: (postgres.E002) Base field for array cannot be a related field.
Any Ideas on how to beat that?
You can't create an array of foreign keys. It is not a Django limitation, it is a PostgreSQL "limitation".
The reason is that a foreign key is not a type, it is a constraint on a field. An array of foreign keys does not make any sense.
The general approach to achieve this is to use an intermediate table that will be used as a link between two others :
Authors(id, name)
Books(id, title, pub_date)
BookAuthors(id, book_id, author_id)
In the above exemple, BookAuthors.book_id is a foreign key to Books.id and BookAuthors.author_id is a foreign key to Authors.id. Thus, the table BookAuthors is used to match an author with a book and vice versa.
Django abstracts this intermediate table with ManyToManyField fields:
class Authors(models.Model):
name = models.CharField(...)
class Books(models.Model):
title = models.CharField(...)
pub_date = models.DateField(...)
authors = models.ManyToManyField('my_app.Authors',
related_name='authored_books')
Behind the scenes, Django will create the intermediate table.
Then, you can get all authors of a book using book.authors.all(), or all books authored by an author using author.authored_books.all().
You have to use ManyToManyField, ArrayField can't be related with another model.

Get objects that are foreign key

I need ot get objects that are foreign keys. Example
class City(models.Model):
.....
class User(models.Model):
city = models.ForeignKeu(City)
.......
Can i get only that cities which are Foreign key to model User with django orm or mysql?
Yes you can, it's all in the Documentation:
https://docs.djangoproject.com/en/1.6/ref/models/querysets/
Provide a readable backward reference to the city model (in your User model change city to this one):
city = models.ForeignKey(City, related_name='user')
Then
cities = City.objects.select_related('user').filter(user__city__isnull=False).all()

Id field in Model Django

I always get a primary column as Id in the Django model. Is there any possibility to change. For ex. for City table I want to have a Primary Key column as city_id.
city_id = models.AutoField(primary_key=True)
The answer is YES,
Something like this:
city_id = models.PositiveIntegerField(primary_key=True)
Here, you are overriding the id. Documentation here
If you’d like to specify a custom primary key, just specify primary_key=True on one of your fields. If Django sees you’ve explicitly set Field.primary_key, it won’t add the automatic id column.
Alternatively, You can always define a model property and use that . Example
class City(models.Model)
#attributes
#property
def city_id(self):
return self.id
and access it as city.city_id where you would normally do city.id
By default, Django gives each model the following field:
id = models.AutoField(primary_key=True)
This is an auto-incrementing primary key.
So for your case is:
city_id = models.AutoField(primary_key=True)
Ofcourse, you can.
city_id = models.BigIntegerField(primary_key=True)