使用场景: 多对多的关系可使用ManyToManyField,其实也能够直接本身手动写一个关联表,可是不若有ManyToManyField字段的话查询会方便不少。python
以学校为例,这里有两个表,一个是专业表,一个是学校表,学校应该包含专业,并且应该是多对多的关系, 以下是学校表:django
class School(MyModel): name = models.CharField(_("校名"), max_length=200, help_text="最多200字") intro = models.CharField(_('简介'), max_length=5000,null=True, blank=True, help_text="最多5000字") base_info = models.CharField(_('基本信息'), max_length=5000, null=True, blank=True, help_text="最多5000字") address = models.ForeignKey(Area, verbose_name=_('所属位置'), null=True, blank=True) hot = models.ManyToManyField(Hot, verbose_name=_('热门'), null=True, blank=True, related_name="school_hot_set") category = models.ManyToManyField(Category, verbose_name=_('类别'), null=True, blank=True, related_name="school_category_set") major = models.ManyToManyField(Major, verbose_name=_('专业'), null=True ,blank=True, related_name="school_major_set", through='SchoolMajor')
这里能看到有多个外键, address为一对多的外键,觉得学校只会有一个位置信息(不考虑分校。。), 热门和类别都是多对多的关系,专业也是多对多的关系,spa
hot 和category为两个特别简单的ManyToManyField。 major由于须要在关系上有自定义属性,因此指定了关系表SchoolMajor:code
class SchoolMajor(MyModel): major = models.ForeignKey(Major, verbose_name=_('专业')) school = models.ForeignKey(School, verbose_name=_('学校')) type = models.IntegerField(_('类型'), choices=((0, '本科'), (1, '研究生'), (2, '本硕'))) create_time = models.DateTimeField(_('建立时间'), auto_now_add=True)
看到除了两个外键外,增长了type和create_time字段。blog
以上为基础的使用方式,详细的能够查看django官方文档:https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/文档
或者我找到的介绍的挺详细的博客:http://luozhaoyu.iteye.com/blog/1510635get
如上例子,查询某个学校下全部专业:school.major.all()便可。 博客
查询包含id为1的专业的全部学校,能够直接经过School.objects.filter(major_id=1), 也能够经过major反查,先获取到id为1的major,而后major.school_major_set.all() 便可。it
有些状况下咱们须要查询出来既有id为1专业的学校 也有id为2专业的学校,这里就可使用filter链:io
School.objects.filter(major_id=1).filter(major_id=2)
若是想查询出只有两个专业的学校:
School.objects.annotate(count=Count("major")).filter(count=2)
结合上面两个,查询出只有专业1和专业2的学校:
School.objects.annotate(count=Count("major"))..filter(major_id=1).filter(major_id=2).filter(count=2)