Reputation: 23
Lets suppose that I have two models named Company and Airplane:
class Company(models.Model):
name= models.CharField(max_length=250)
location=models.Charfield(max_length=250)
class Airplane(models.Model):
company = models.ForeignKey(Company, on_delete=models.RESTRICT)
number = models.IntegerField(unique=True)
I want the number in Airplane model to be unique but just in the same company, an airplane from another company can have the same number. Is it that possible?
Upvotes: 2
Views: 706
Reputation: 173
Rather than requiring Airplane number field to be unique, you could enforce a multiple-column uniqueness constraint. In other words, the (company, number) pair should be unique and another default auto-incremented column could be used as a primary key for the Airplane table.
See the answer here: How to define two fields "unique" as couple
Upvotes: 2
Reputation: 56948
You could create a UNIQUE Index (at least in native SQLite) for the airplane table comprised of the company and number columns.
I haven't used Django so I'm unsure whether or not a multi-column index is possible.
unique_together
in DJango as per Django composite unique on multiple model fields orUniqueConstraint
https://docs.djangoproject.com/en/3.1/ref/models/constraints/#django.db.models.UniqueConstraintHowever for native SQLite code here is some that demonstrates the underlying principle/operation:-
DROP INDEX IF EXISTS airplane_number_company;
DROP TABLE IF EXISTS airplane;
DROP TABLE IF EXISTS company;
CREATE TABLE IF NOT EXISTS company (name TEXT UNIQUE, location TEXT);
CREATE TABLE IF NOT EXISTS airplane (company REFERENCES company(name), number INTEGER);
CREATE UNIQUE INDEX IF NOT EXISTS airplane_number_company ON airplane(company,number);
INSERT INTO company VALUES('company1','England'),('company2','America');
INSERT INTO airplane VALUES('company1',100),('company1',200),('company2',100),('company2',200);
SELECT * FROM airplane JOIN company ON airplane.company = company.name;
INSERT OR IGNORE INTO airplane VALUES('company1',100),('company1',500);
SELECT * FROM airplane JOIN company ON airplane.company = company.name;
The first SELECT will display the 4 rows that have been added showing that airplanes with the same number but different company can be added.
After that select an attempt is made to insert two new airplane rows. One row using the same company and number as an existing airplane run the other row using an unused combination.
The second SELECT then displays the result showing that only 1 of the two rows has been added. The fisrt row cannot be added due to the airplane_number_company index the OR IGNORE
allowing the failed attempt to be ignored.
The log from running the above is :-
DROP INDEX IF EXISTS airplane_number_company
> OK
> Time: 0s
DROP TABLE IF EXISTS airplane
> OK
> Time: 0s
DROP TABLE IF EXISTS company
> OK
> Time: 0s
CREATE TABLE IF NOT EXISTS company (name TEXT UNIQUE, location TEXT)
> OK
> Time: 0.11s
CREATE TABLE IF NOT EXISTS airplane (company REFERENCES company(name), number INTEGER)
> OK
> Time: 0.096s
CREATE UNIQUE INDEX IF NOT EXISTS airplane_number_company ON airplane(company,number)
> OK
> Time: 0.085s
INSERT INTO company VALUES('company1','England'),('company2','America')
> Affected rows: 2
> Time: 0.073s
INSERT INTO airplane VALUES('company1',100),('company1',200),('company2',100),('company2',200)
> Affected rows: 4
> Time: 0.074s
SELECT * FROM airplane JOIN company ON airplane.company = company.name
> OK
> Time: 0.001s
INSERT OR IGNORE INTO airplane VALUES('company1',100),('company1',500)
> Affected rows: 1
> Time: 0.082s
SELECT * FROM airplane JOIN company ON airplane.company = company.name
> OK
> Time: 0s
Upvotes: 0