Django餐厅应用创建Order报错:需传入Dish实例而非字符串
Django餐厅应用ForeignKey赋值报错问题解决
我正在开发基于Django的餐厅应用,其中一个视图用于接收Ajax请求。从请求中获取菜品名称后,尝试将其存入新创建的Order对象,但一直报错:ValueError: Cannot assign "'pasta'": "Order.dish_name" must be a "Dish" instance。已尝试修复两天仍未找到原因,希望知晓问题所在。
相关代码
models.py
from django.db import models class Table( models.Model ) : number = models.IntegerField( primary_key= True) def __str__( self ) : return str(self.number) class Dish(models.Model ) : name = models.CharField( primary_key= True, max_length= 50 ) price = models.FloatField() type = models.CharField( max_length= 50 ) gluten = models.BooleanField( null= False) lactose = models.BooleanField( null= False) def __str__( self ) : return self.name class Meal(models.Model ) : start = models.TimeField() end = models.TimeField(blank= True, null= True, default= None) table = models.ForeignKey(Table, on_delete=models.CASCADE) def __str__( self ) : return str(self.table.number) class Order(models.Model): request_time = models.TimeField() kitchen_start_time = models.TimeField(blank= True, null= True, default= None) delivery_time = models.TimeField(blank= True, null= True, default= None) dish_name = models.ForeignKey(Dish, null= True, blank= True, default= None, on_delete=models.CASCADE) table = models.ForeignKey(Table, null= True, default= None, on_delete=models.CASCADE) def __str__(self): return str(self.table.number)
main.js
$(".special").click(function (e){ var x= e.target.id $.ajax({ type: 'POST', data: { 'dishes' : x, }, success: function(response){ console.log(response); }, error: function(error){ console.log(error); }, }); e.preventDefault(); } )
HTML片段
{% for d in dishes %} <div class="cell"> <a href=# class="special" id='{{d.name}}' > {{d.name}}</a> </div> {% endfor %}
视图代码
def open(request, number): tav = Table.objects.get(number = number) p = Meal(table=tav, start=datetime.now()) p.save() dishes = Dish.objects.all().order_by('type') if request.method == 'POST': clicked_dish =request.POST.get('dishes') new_order= Order(request_time=datetime.now(), dish_name= clicked_dish, table=tav) new_order.save() return render(request, 'nuovo.html', {'dishes': dishes, 'table': tav})
URL配置
urlpatterns = [ re_path(r'^admin/', admin.site.urls), re_path(r'home/', views.home), re_path(r'^new/',views.index, name='index'), re_path(r'^open/(\d+)/$',views.open, name='open'), ]
问题原因
Order.dish_name是指向Dish模型的外键字段,Django要求外键字段必须赋值对应模型的实例对象,而你直接把从POST请求里拿到的菜品名称字符串(比如'pasta')赋值给它,不符合外键的赋值规则,因此抛出错误。
解决方案
通过菜品名称查询到对应的Dish实例,再将该实例赋值给Order.dish_name,修改后的视图代码如下:
def open(request, number): tav = Table.objects.get(number=number) # 注:当前每次请求都会创建新Meal,若不符合业务逻辑可调整至非POST分支 p = Meal(table=tav, start=datetime.now()) p.save() dishes = Dish.objects.all().order_by('type') if request.method == 'POST': clicked_dish_name = request.POST.get('dishes') # 通过菜品名称查询Dish实例(Dish主键为name) try: dish_instance = Dish.objects.get(name=clicked_dish_name) new_order = Order(request_time=datetime.now(), dish_name=dish_instance, table=tav) new_order.save() except Dish.DoesNotExist: # 处理菜品不存在的异常,比如返回提示 pass return render(request, 'nuovo.html', {'dishes': dishes, 'table': tav})
额外优化建议
- 修正Meal创建逻辑:当前代码每次进入
open视图都会创建新Meal,包括Ajax请求时,建议移至非POST请求分支,避免重复创建。 - 添加CSRF令牌:Django默认开启CSRF保护,Ajax请求需携带令牌才能正常访问。在HTML中添加
{% csrf_token %},并修改JS代码:
$(".special").click(function (e){ var x= e.target.id var csrftoken = $("[name=csrfmiddlewaretoken]").val(); $.ajax({ type: 'POST', headers: { "X-CSRFToken": csrftoken }, data: { 'dishes' : x, }, success: function(response){ console.log(response); }, error: function(error){ console.log(error); }, }); e.preventDefault(); } )
- 时间字段替换:
request_time等字段使用TimeField仅能存储时间,建议改用DateTimeField存储完整的日期和时间,更符合订单记录需求。
内容的提问来源于stack exchange,提问作者bhe
相关产品推荐
相关产品推荐

