如何在Django中通过三张表关联查询,按CategoryManager筛选课程?
问题背景
我们定义了以下三个Django模型:
class Category(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=200) class CategoryManager(models.Model): category = models.ForeignKey(Category, on_delete=models.PROTECT, verbose_name=_('Course Category'), related_name="category_categorymanager") manager = models.ForeignKey(_user, verbose_name=_('Category Manager'), on_delete=models.CASCADE, related_name="user_categorymanager") class Course(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=200, verbose_name=_('Course Name')) ... price = models.DecimalField(max_digits=7, decimal_places=2, verbose_name=_('Course Price'), blank=True, null=True) slug = models.SlugField(unique=True, blank=True) category = models.ForeignKey(Category, related_name='courses_category', on_delete=models.PROTECT)
需求是在Course的Admin后台中,通过CategoryManager筛选出当前登录用户负责管理的分类下的所有课程。现有Admin代码片段如下:
@admin.register(Course) class CourseAdmin(admin.ModelAdmin): def get_queryset(self, request): category_manager_list=CategoryManager.objects.filter(manager=request.user) ... return ....
解决方案
可以通过以下两种方式补全get_queryset方法,实现需求:
方式一:直接通过关联查询过滤
先获取当前用户管理的所有分类,再筛选对应分类下的课程:
@admin.register(Course) class CourseAdmin(admin.ModelAdmin): def get_queryset(self, request): # 获取当前用户有权管理的所有分类 managed_categories = Category.objects.filter( category_categorymanager__manager=request.user ) # 基于默认查询集,追加分类过滤条件 qs = super().get_queryset(request) return qs.filter(category__in=managed_categories)
方式二:通过中间表提取分类ID过滤
如果要保留原有的category_manager_list变量,可提取其中的分类ID来过滤课程:
@admin.register(Course) class CourseAdmin(admin.ModelAdmin): def get_queryset(self, request): category_manager_list = CategoryManager.objects.filter(manager=request.user) # 提取所有关联分类的ID category_ids = category_manager_list.values_list('category__id', flat=True) # 过滤出对应分类下的课程 qs = super().get_queryset(request) return qs.filter(category__id__in=category_ids)
说明
- 两种方式均基于Django的反向关联查询逻辑,确保只显示当前用户管理分类下的课程。
- 调用
super().get_queryset(request)是为了保留Admin默认的权限过滤逻辑,再叠加自定义的分类筛选规则。
内容的提问来源于stack exchange,提问作者fdas
相关产品推荐
相关产品推荐

