我正在创建一个使用Django模板引擎的web应用程序。说到这里,我的一个模型叫做Order
。除其他模型外,Order
模型还使用Food
模型-这是ManyToMany
关系。Food
模型使用Category
模型来定义食品类别(应该包含披萨,汉堡,葡萄酒,啤酒等食品类别)-这也是ManyToMany
关系。
现在,我试图创建一个表单,其中用户将显示一个表单与分离的类别。到目前为止,Food
模型中的所有食物都是一个接一个地显示出来的,一个在另一个的下面。它们没有在表单模板中分类。目前,它们默认显示为一个简单的食物列表,用户可以选择其中的任何一种。我希望用户可以选择他们想要的任何食物,但要分类显示(Pizza类别下的所有披萨,burgers类别下的所有汉堡,等等)。
我的models.py
是这样的:
class Category(models.Model):
"""
Model for food categories
"""
name = models.CharField(max_length=100)
description = models.TextField(max_length=300)
date_created = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return f"{self.name} / {self.description[0 : 50]}..."
class Food(models.Model):
"""
Model for foods
"""
name = models.CharField(max_length=150)
description = models.TextField(max_length=400)
category = models.ManyToManyField(Category)
price = models.FloatField()
date_created = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return f"{self.name} / {', '.join(self.category.values_list('name', flat=True))} / {self.price} EUR"
class Order(models.Model):
"""
Model for orders
"""
order_statuses = [
("PR", "Status 1"),
("PS", "Status 2"),
]
customer_name = models.CharField(max_length=255)
customer_email = models.EmailField(blank=True)
ordered_foods = models.ManyToManyField(Food)
table = ForeignKey(Table, on_delete=models.CASCADE)
status = models.CharField(choices=order_statuses,
default="PR",
max_length=2)
total_price = models.FloatField(editable=False, default=0)
date_created = models.DateTimeField(auto_now=True)
date_completed = models.DateTimeField(blank=True,
default=datetime.datetime.strptime('2099-12-31 00:00:00', '%Y-%m-%d %H:%M:%S'))
def __str__(self) -> str:
return f"{self.id} / {self.customer_name} / {self.table.name} {self.table.number} / STATUS: {self.get_status_display()} / {self.total_price} EUR"
我的create_order.html
(模板的形式,看起来像这样):
<form method="post">
{% csrf_token %}
{{ form | crispy }}
<button type="submit" class="btn btn-success">Submit</button>
</form>
我也使用crispy_forms
,如果它有任何不同。
我愿意接受任何关于如何在表单模板中对食物进行分类的建议。
Thank you very much
要做到这一点,您需要做以下更改
- 在
models.py
中将related_name='foods'
添加到Food模型中的类别中,如下所示:
category = models.ManyToManyField(Category, related_name='foods')
我们将在后面使用related_name
- 在
forms.py
中添加类别字段到您的订单中,这样您就会有这样的内容:
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = [
'customer_name',
'customer_email',
'category',
'ordered_foods',
'ordered_foods',
'status',
]
# add this line and don't forget to add category to the field or use '__all__'
category = forms.ModelChoiceField(queryset=Category.objects.all())
- 现在我们将使用AJAX,你需要导入jQuery,将这段代码添加到你的js文件:
$(document).ready(function(){
var $category = $('#id_category');
function updateFoodChoices() {
var output = [];
output.push(`<option value="" disabled selected>Please select category</option>`)
$('#id_ordered_foods').html(output.join(''));
var selected = $category.val();
if (selected) {
$.ajax({
type: 'GET',
url: `/foodbycat/?cat_id=${selected}`,
success: function(response) {
const foods = response.data
$('#id_ordered_foods').empty()
var output = [];
foods.forEach(food => {
output.push(`<option value="${food.id}">${food.name} / ${food.price} EUR</option>`);
});
$('#id_ordered_foods').html(output.join(''));
},
error: function(error) {
console.log('error', error)
}
});
}
}
updateFoodChoices();
$category.change(updateFoodChoices);
});
这段代码将根据所选类别更新食物选择,为了让它工作,我们需要在views.py
- 将此功能添加到
views.py
:
def ajaxGetFoodByCategory(request):
cat_id = request.GET.get('cat_id')
if cat_id is not None:
category = get_object_or_404(Category, id=cat_id)
foods = category.foods.all()
# data = serializers.serialize('json', category.foods.all())
data = []
for food in foods:
item = {
'id': food.id,
'name': food.name,
'price': str(food.price),
}
data.append(item)
print(data)
return JsonResponse({'data': data})
else:
return HttpResponseBadRequest()
这段代码将获取所选类别的id并返回包含该类别的食物列表
- 好了,我们差不多完成了我们只需要将这一行添加到
urls.py
path('foodbycat/', views.ajaxGetFoodByCategory, name='foodby-ctg'),
您需要检查添加到urls.py
的路径是否与js代码中的url匹配