django的ManyToManyField

使用场景: 多对多的关系可以使用ManyToManyField,其实也可以直接自己手动写一个关联表,但是不如有ManyToManyField字段的话查询会方便很多。

以学校为例,这里有两个表,一个是专业表,一个是学校表,学校应该包含专业,而且应该是多对多的关系,  如下是学校表:

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为一对多的外键,以为学校只会有一个位置信息(不考虑分校。。), 热门和类别都是多对多的关系,专业也是多对多的关系,

hot 和category为两个特别简单的ManyToManyField。 major因为需要在关系上有自定义属性,所以指定了关系表SchoolMajor:

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字段。


以上为基础的使用方式,详细的可以查看django官方文档:https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/

或者我找到的介绍的挺详细的博客:http://luozhaoyu.iteye.com/blog/1510635


ManyToMany的查询

如上例子,查询某个学校下所有专业:school.major.all()即可。 

查询包含id为1的专业的所有学校,可以直接通过School.objects.filter(major_id=1), 也可以通过major反查,先获取到id为1的major,然后major.school_major_set.all() 即可。

有些情况下我们需要查询出来既有id为1专业的学校 也有id为2专业的学校,这里就可以使用filter链:

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)

参考资料:http://stackoverflow.com/questions/5301996/how-to-do-many-to-many-django-query-to-find-book-with-2-given-authors





你可能感兴趣的:(django,manytomany)