Django 过滤器也可以获取反向外键,或者更好的方式来组合相关的数据库信息?

Django filter that also grabs a reverse ForeignKey, or better way to combine associated database info?

我正在做一些后端 Django 工作,需要我通过过滤获取 Employee,但我还需要获取与 Employee 关联的 EmployeeAddress 对象.我想知道这是否可以在单个查询中实现。我需要将员工地址和员工信息放在一个组合的单个字典中,以便在前端使用 JS 访问。

我有这样的模型,

Class Employee(models.model):
    first_name
    last_name
    email
    

Class EmployeeAddress(models.model):
    employee = models.ForeignKey(Employee):
    street
    city
    state

我有一个观点,有点做这个工作,但是在将两个单独的 QuerySets 合并到一个包含所有值的列出的字典中时遇到了问题。

我希望有一种方法可以获取 EmployeeAddress 而无需编写第二个查询,而只需在第一个 employee_list 查询中获取相关数据?

def employee_ajax_list(request):
    email = request.GET.get('email', None)
    employee_list = Employee.objects.filter(email=email)
    employee_address = EmployeeAddress.objects.filter(employee_id__in=employee_list).values(
        'street', 'city', 'state',)
    # this chain kinda works, but splits them into 2 separate dictionaries?
    employee_info = list(chain(employee_list.values(), employee_address))
    data = {
        'employee_list': employee_info
    }
    return JsonResponse(data)

只是在寻找一些建议,让这项工作更顺利一些!

也许像这样的东西在单个查询中会更好一些:

employee_info = EmployeeAddress.objects.filter(employee__email=email).values("employee__email", "employee__<another_field>", "street", "city", "state")

data = {
    'employee_list': employee_info
}

最好的方法是使用 DRF 序列化程序:

class EmployeeAddressSerializer(serializers.ModelSerializer):
    class Meta:
        fields = "__all__"
        model = Employee


class EmployeeSerializer(serializers.ModelSerializer):
    # you should add related_name="addresses" in the
    # foreignkey if you want this works.
    addresses = EmployeeAddressSerializer(many=True)

    class Meta:
        fields = "__all__"
        model = Employee

然后使用:

employee = Employee.objects.filter(email=email).last()
return JsonResponse(EmployeeSerializer(employee).data)

更改此行

employee = models.ForeignKey(Employee)

employee = models.ForeignKey(Employee, related_name="address")

这样您就可以通过在常规代码中执行 employee.address 或在查询中执行 employee__address 来访问员工的地址。

例如:

Employee.objects
    .filter(email=email)
    .exclude(address=None)
    .values(
        'email', 
        'name', 
        'address__street', 
        'address__city', 
        'address__state'
    )

.exclude() 子句是为了防止有人没有设置地址。)

应该输出如下内容:

<QuerySet [{'email': 'johnsmith@example.com', 
'name': 'John Smith', 'address__street': 
'123 Maple St', 'address__city': 'Springfield', 
'address__state': 'MO'}]>