You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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})

额外优化建议

  1. 修正Meal创建逻辑:当前代码每次进入open视图都会创建新Meal,包括Ajax请求时,建议移至非POST请求分支,避免重复创建。
  2. 添加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();    
}
)
  1. 时间字段替换:request_time等字段使用TimeField仅能存储时间,建议改用DateTimeField存储完整的日期和时间,更符合订单记录需求。

内容的提问来源于stack exchange,提问作者bhe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 17:45:44