django -- 多对多关系的实现
在django中表和表之间的多对多关系有两种实现方案:
方案一:直接使用django自动实现的多对多关系。
方案二:自己写连接表、然而告诉django在实现多对多关系时要使用的连接表。
一、方案一:
model的定义
from django.db import models class Person(models.Model): name= models.CharField(max_length=16) birthday=models.DateField() class Group(models.Model): name= models.CharField(max_length=16) members = models.ManyToManyField(Person)
对应的SQL代码:
BEGIN; -- -- Create model Group -- CREATE TABLE "polls_group" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL); -- -- Create model Person -- CREATE TABLE "polls_person" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL, "birthday" date NOT NULL); -- -- Add field members to group -- CREATE TABLE "polls_group_members" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "group_id" integer NOT NULL REFERENCES "polls_group" ("id"), "person_id" integer NOT NULL REFERENCES "polls_person" ("id")); CREATE UNIQUE INDEX "polls_group_members_group_id_person_id_ce176f60_uniq" ON "polls_group_members" ("group_id", "person_id"); CREATE INDEX "polls_group_members_group_id_f4695d83" ON "polls_group_members" ("group_id"); CREATE INDEX "polls_group_members_person_id_fb30aa04" ON "polls_group_members" ("person_id"); COMMIT; -- ---------------------------- delimiter // create procedure sp_a(a int) BEGIN insert into t1(x,a) values(100,a); end // delimiter ;
二、方案二:
model的定义
from django.db import models class Person(models.Model): name= models.CharField(max_length=16) birthday=models.DateField() def __str__(self): return self.name class Group(models.Model): name= models.CharField(max_length=16) members = models.ManyToManyField(Person,through=MemberShip) class MemberShip(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_join=models.DateTimeField() invite_reason=models.CharField(max_length=100)
对应的SQL代码:
BEGIN; -- -- Create model Group -- CREATE TABLE "polls_group" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL); -- -- Create model MemberShip -- CREATE TABLE "polls_membership" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "date_join" datetime NOT NULL, "invite_reason" varchar(100) NOT NULL, "group_id" integer NOT NULL REFERENCES "polls_group" ("id")); -- -- Create model Person -- CREATE TABLE "polls_person" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL, "birthday" date NOT NULL); -- -- Add field person to membership -- ALTER TABLE "polls_membership" RENAME TO "polls_membership__old"; CREATE TABLE "polls_membership" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "date_join" datetime NOT NULL, "invite_reason" varchar(100) NOT NULL, "group_id" integer NOT NULL REFERENCES "polls_group" ("id"), "person_id" integer NOT NULL REFERENCES "polls_person" ("id")); INSERT INTO "polls_membership" ("id", "date_join", "invite_reason", "group_id", "person_id") SELECT "id", "date_join", "invite_reason", "group_id", NULL FROM "polls_membership__old"; DROP TABLE "polls_membership__old"; CREATE INDEX "polls_membership_group_id_19f13d47" ON "polls_membership" ("group_id"); CREATE INDEX "polls_membership_person_id_fa058fab" ON "polls_membership" ("person_id"); -- -- Add field members to group -- CREATE TABLE "polls_group_members" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "group_id" integer NOT NULL REFERENCES "polls_group" ("id"), "person_id" integer NOT NULL REFERENCES "polls_person" ("id")); CREATE UNIQUE INDEX "polls_group_members_group_id_person_id_ce176f60_uniq" ON "polls_group_members" ("group_id", "person_id"); CREATE INDEX "polls_group_members_group_id_f4695d83" ON "polls_group_members" ("group_id"); CREATE INDEX "polls_group_members_person_id_fb30aa04" ON "polls_group_members" ("person_id"); COMMIT;
三、由上面的SQL可以看出django来只是定义了memberShip模式对应的表、它自己也并没有放弃自己的那一套:
model 的定义:
from django.db import models class Person(models.Model): name= models.CharField(max_length=16) birthday=models.DateField() class Meta(): db_table="person" class Group(models.Model): name= models.CharField(max_length=16) members = models.ManyToManyField(Person,through='MemberShip') class Meta(): db_table="group" class MemberShip(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_join=models.DateTimeField() invite_reason=models.CharField(max_length=100) class Meta(): db_table="membership"
对应的SQL代码:
BEGIN; -- -- Create model Group -- CREATE TABLE "group" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL); -- -- Create model MemberShip -- CREATE TABLE "membership" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "date_join" datetime NOT NULL, "invite_reason" varchar(100) NOT NULL, "group_id" integer NOT NULL REFERENCES "group" ("id")); -- -- Create model Person -- CREATE TABLE "person" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL, "birthday" date NOT NULL); -- -- Add field person to membership -- ALTER TABLE "membership" RENAME TO "membership__old"; CREATE TABLE "membership" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "date_join" datetime NOT NULL, "invite_reason" varchar(100) NOT NULL, "group_id" integer NOT NULL REFERENCES "group" ("id"), "person_id" integer NOT NULL REFERENCES "person" ("id")); INSERT INTO "membership" ("id", "date_join", "invite_reason", "group_id", "person_id") SELECT "id", "date_join", "invite_reason", "group_id", NULL FROM "membership__old"; DROP TABLE "membership__old"; CREATE INDEX "membership_group_id_786fce67" ON "membership" ("group_id"); CREATE INDEX "membership_person_id_8ed25d16" ON "membership" ("person_id"); -- -- Add field members to group -- ALTER TABLE "group" RENAME TO "group__old"; CREATE TABLE "group" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(16) NOT NULL); INSERT INTO "group" ("id", "name") SELECT "id", "name" FROM "group__old"; DROP TABLE "group__old"; COMMIT;
总结:
1、在定义模式时指定数据库中的表名是一个好的习惯、这样django就不会建立一些不需要的表了。
2、对于多对多关系还是自己实现多对多关系比较好、一来可以保存一些额外的有用信息、表名也更加统一。
----