我的模型的简化版本如下:
class Order (models.Model):
customer = models.ForeignKey("Customer", on_delete=models.RESTRICT)
request_date = models.DateField()
price = models.DecimalField(max_digits=10, decimal_places=2)
@property
def agent_name(self):
assignment = Assignment.objects.get(assig_year = self.request_date.year, customer = self.customer)
if assignment is not None:
return assignment.sales_agent.name + ' ' + assignment.sales_agent.surname
else:
return 'ERROR'
class Company (models.Model):
pass
class Customer (Company):
pass
class Assignment (models.Model):
assig_year = models.PositiveSmallIntegerField()
customer = models.ForeignKey("Customer", on_delete=models.CASCADE)
sales_agent = models.ForeignKey("Agent", on_delete=models.CASCADE)
class Employee (models.Model):
name = models.CharField(max_length=32)
surname = models.CharField(max_length=32)
class Agent (Employee):
pass
在我的一种观点中,我通过列出相应的销售代理、客户、日期和价格来显示所有订单,如下所示:
def GetOrders(request):
orders = Order.objects.order_by('-request_date')
template = loader.get_template('orders.html')
context = {
'orders' : orders,
}
return HttpResponse(template.render(context,request))
orders.html 看起来像这样:
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<main>
<table>
<thead>
<th>Agent</th>
<th>Customer</th>
<th>Date</th>
<th>Price</th>
</thead>
<tbody>
{% for x in orders %}
<td>{{ x.agent_name }}</td>
<td>{{ x.customer.name }}</td>
<td>{{ x.request_date }}</td>
<td>{{ x.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
</body>
</html>
现在我想在 html 中添加一些过滤功能,以便仅选择我感兴趣的销售代理,但这是我的第一个 Django 项目,我不知道如何处理我刚接触的所有关系通过以检查销售代理的名称。我尝试利用 agent_name 属性,如下所示:
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<main>
<div class="filters">
<form action="" method="GET">
<div class="row">
<div class="col-xl-3">
<label>Agent:</label>
<input type="text" class="form-control" placeholder="Name" name="name" {% if name %} value = "{{ name }}" {% endif %}>
</div>
<div class="col-xl-2" style="padding-top: 2%;">
<button type="submit" class="btn custom-btn">Filter</button>
</div>
</div>
</form>
</div>
<p/>
<table>
<thead>
<th>Agent</th>
<th>Customer</th>
<th>Date</th>
<th>Price</th>
</thead>
<tbody>
{% for x in orders %}
<td>{{ x.agent_name }}</td>
<td>{{ x.customer.name }}</td>
<td>{{ x.request_date }}</td>
<td>{{ x.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
</body>
</html>
我的观点现在变成这样:
def GetOrders(request):
orders = Order.objects.order_by('-request_date')
com = request.GET.get('name')
if com != '' and com is not None:
orders = orders.filter(Q(agent_name__icontains=com))
template = loader.get_template('orders.html')
context = {
'orders' : orders,
}
return HttpResponse(template.render(context,request))
但似乎我不能将它用作过滤条件,因为它不是真正的模型字段,并且我得到一个 FieldError 返回(“无法将关键字“agent_name”解析为字段”)。
有什么想法吗?
简短的回答是:您不能按照描述执行此操作,因为 @property 函数是在执行查询后通过 python 设置的,即它使用返回的查询作为函数的数据。
此外,您的属性还会对每个 agent_name 进行 sql 调用。 对于一个代理来说不是问题,但是循环 50 个代理会效率很低。
订单和分配之间似乎存在某种关系,因此您可以通过外键将它们连接起来,就像处理订单和客户一样。 然后将一个新字段注释到查询集中
from django.db.models.functions import Concat
from django.db.models import Value
com = request.GET.get('name')
if com != '' and com is not None:
#start definition of orders with ( so we can break up the line for readability
orders = (
Order.objects.annotate(
#Combine firstname, space, and last name into new field
full_name = Concat(
'order__assignment__sales_agent__name',
Value(' '),
'order__assignment__sales_agent__surname'
)
)
#filter on our annotated field from the form
.filter(full_name__icontains=com)
.order_by('-request_date')
)