django - Django (DRF) 多对多字段选择/限制
问题描述
使用 Django REST Framework 我想知道是否可以将ManyToMany
模型上字段的选择/选项限制为特定的QuerySet
?
使用下面的模型(向下滚动查看模型),我很好奇是否可以在模型定义中定义此限制,以实现以下目标:
# Having the following Employee instance
emp = Employee(...)
# Should return only the instances with value 'case' in EmployeeSubstitute.type field
emp.substitute_case.all()
# Should return only the instances with value 'phone' in EmployeeSubstitute.type field
emp.substitute_phone.all()
楷模:
class Employee(models.Model):
substitute_case = models.ManyToMany(through=EmployeeSubstitute, ...)
substitute_phone = models.ManyToMany(through=EmployeeSubstitute, ...)
class EmployeeSubstitute(models.Model):
from = models.ForeignKey(Employee, ...)
to = models.ForeignKey(Employee, ...)
type = models.CharField(choices=..., ...) # choose between type 'case' and 'phone'
我看到有limit_choices_to
参数,但这不是我想要的,因为它只会影响使用 ModelForm 或管理员时显示的选项。
解决方案
好吧,ManyToManyField
返回相关对象和文档状态
默认情况下,Django 在访问相关对象(即choice.question)时使用Model._base_manager 管理器类的实例,而不是相关对象上的_default_manager。这是因为 Django 需要能够检索相关对象,即使它会被默认管理器过滤掉(因此无法访问)。
如果普通的基础管理器类(django.db.models.Manager)不适合你的情况,你可以通过设置 Meta.base_manager_name 告诉 Django 使用哪个类。
查询相关模型或访问一对多或多对多关系时不使用基本管理器。例如,如果教程中的 Question 模型有一个已删除的字段和一个基本管理器,它过滤掉已删除的实例=True,则像 Choice.objects.filter(question__name__startswith='What') 这样的查询集将包含与已删除问题相关的选项。
所以如果我没看错的话,不,这是不可能的。
当您进行查询并through
在您ManyToManyField
的through
. 我在文档中找不到它,但我记得看过几次。
substitute_case
并且substitute_phone
是属于替代品的东西,它是它的类型。所以只需这样做,而不是在Employee
.
from django.db import models
class SubstituteTypes(models.TextChoices):
case = "case", "case"
phone = "phone", "phone"
class EmployeeSubstituteQueryset(models.QuerySet):
def from_employee(self, e):
return self.filter(_from=e)
def case(self):
return self.filter(type=SubstituteTypes.case)
def phone(self):
return self.filter(type=SubstituteTypes.phone)
class Employee(models.Model):
substitute = models.ManyToManyField(through='EmployeeSubstitute', to='self')
class EmployeeSubstitute(models.Model):
_from = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='a')
to = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name='b')
type = models.CharField(choices=SubstituteTypes.choices, max_length=5, db_index=True)
objects = EmployeeSubstituteQueryset.as_manager()
然后,一旦你得到你的emp
对象(或只有它的 id),你可以做
EmployeeSubstitute.objects.from_employee(emp).case().all()
这是在 Django 哲学中设计的。
推荐阅读
- regex - 添加到正则表达式模式,因此字符串可能不包含句点
- html - 如何使用 flexdashboard 添加指向徽标的链接?
- angular - ngx-leaflet 在 Dropbox 选择的值更改后重新加载地图
- java - Spring Security 登录页面 url 参数
- reset - AOG 隐式帐户链接 - 如何重置?
- java - Springboot 503 服务不可用
- java - HMAC解密
- html - 在移动版中将菜单居中,但在桌面版中不居中
- r - 将来自 Fisher 测试的多个 p 值合并到原始数据
- c++ - 如何使用 C++ 将一个字符串替换为 csv 文件中的另一个字符串