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

Django REST框架餐饮订单开发遇阻:订单创建功能求助

Hey there! Let's work through your Django REST Framework food ordering project bottleneck together. Based on what you've shared, it sounds like the main sticking point is finalizing the Food Orders model and tying everything together properly. Here's a step-by-step guide to get you back on track:

1. Fix the "Food Orders" Model (Replace the Incomplete fake_id)

First off, that fake_id field you mentioned is likely meant to link orders to specific food/drink items. Instead of a vague fake ID, we'll create a proper order item junction model to connect your Orders model with individual food or drink products—this is standard for order systems where one order can have multiple items.

First, if you don't already have them, define your core product models:

from django.db import models

class Food(models.Model):
    food_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    description = models.TextField(blank=True)

class Drink(models.Model):
    drink_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    is_alcoholic = models.BooleanField(default=False)

Now create the OrderItem model (this replaces your incomplete Food Orders model):

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey

class OrderItem(models.Model):
    item_id = models.AutoField(primary_key=True)  # Replaces your fake_id with a proper primary key
    order = models.ForeignKey(
        'Orders', 
        on_delete=models.CASCADE, 
        related_name='items'  # Lets you access order.items to get all items in an order
    )
    # Use GenericForeignKey to support both Food and Drink items in the same order
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    item = GenericForeignKey('content_type', 'object_id')
    quantity = models.PositiveIntegerField(default=1)
    subtotal = models.DecimalField(max_digits=8, decimal_places=2, editable=False)

    def save(self, *args, **kwargs):
        # Auto-calculate subtotal when saving the item
        self.subtotal = self.item.price * self.quantity
        super().save(*args, **kwargs)
2. Refine Your Orders Model

Your current Orders model is missing some critical fields and has a risky on_delete setting. Let's update it:

class Orders(models.Model):
    order_id = models.AutoField(primary_key=True)
    customer = models.ForeignKey(
        'Customers', 
        on_delete=models.PROTECT,  # Prevent deleting customers who have orders
        related_name='orders'
    )
    date = models.DateTimeField(auto_now_add=True)
    total = models.DecimalField(max_digits=10, decimal_places=2, editable=False)
    status = models.CharField(
        max_length=20,
        choices=[
            ('pending', 'Pending'),
            ('completed', 'Completed'),
            ('cancelled', 'Cancelled')
        ],
        default='pending'
    )

    def save(self, *args, **kwargs):
        # Auto-calculate total order price from items
        self.total = sum(item.subtotal for item in self.items.all())
        super().save(*args, **kwargs)
3. Build Serializers for Django REST Framework

Next, we need serializers to handle converting model data to JSON (and vice versa) for your API:

Product Serializers

from rest_framework import serializers
from .models import Food, Drink

class FoodSerializer(serializers.ModelSerializer):
    class Meta:
        model = Food
        fields = ['food_id', 'name', 'price', 'description']

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        fields = ['drink_id', 'name', 'price', 'is_alcoholic']

Order Item & Order Serializers

from .models import OrderItem, Orders, Customers

class OrderItemSerializer(serializers.ModelSerializer):
    item = serializers.SerializerMethodField()

    class Meta:
        model = OrderItem
        fields = ['item_id', 'item', 'quantity', 'subtotal']

    def get_item(self, obj):
        # Return the correct serializer data based on whether it's food or drink
        if obj.content_type.model == 'food':
            return FoodSerializer(obj.item).data
        elif obj.content_type.model == 'drink':
            return DrinkSerializer(obj.item).data
        return None

class CustomerSerializer(serializers.ModelSerializer):
    # Show the associated user's username (adjust based on your Users model)
    user = serializers.StringRelatedField()

    class Meta:
        model = Customers
        fields = ['id', 'user']

class OrderSerializer(serializers.ModelSerializer):
    customer = CustomerSerializer(read_only=True)
    items = OrderItemSerializer(many=True, read_only=True)
    total = serializers.DecimalField(max_digits=10, decimal_places=2, read_only=True)

    class Meta:
        model = Orders
        fields = ['order_id', 'customer', 'date', 'status', 'total', 'items']

    def create(self, validated_data):
        # Handle creating an order with its items (uses a transaction to avoid partial saves)
        from django.db import transaction
        from django.contrib.contenttypes.models import ContentType

        with transaction.atomic():
            # Get items data from the request
            items_data = self.context['request'].data.get('items', [])
            # Create the base order
            order = Orders.objects.create(**validated_data)
            
            # Create each order item
            for item_data in items_data:
                content_type = ContentType.objects.get(model=item_data['content_type'])
                product = content_type.get_object_for_this_type(id=item_data['object_id'])
                OrderItem.objects.create(
                    order=order,
                    content_type=content_type,
                    object_id=item_data['object_id'],
                    quantity=item_data['quantity']
                )
            
            # Trigger total calculation
            order.save()
            return order
4. Set Up Views & Routes

Use Django REST's ModelViewSet to quickly build CRUD endpoints for orders:

ViewSet

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from .models import Orders
from .serializers import OrderSerializer

class OrderViewSet(viewsets.ModelViewSet):
    serializer_class = OrderSerializer
    queryset = Orders.objects.all().prefetch_related('items')  # Optimize database queries
    permission_classes = [IsAuthenticated]  # Only logged-in users can create orders

    def perform_create(self, serializer):
        # Auto-link the order to the current user's Customers profile
        customer = Customers.objects.get(user=self.request.user)
        serializer.save(customer=customer)

Routes

Add this to your app's urls.py:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import OrderViewSet

router = DefaultRouter()
router.register(r'orders', OrderViewSet)

urlpatterns = [
    path('', include(router.urls)),
]
5. Key Tips to Avoid Headaches
  • Transaction Safety: We used transaction.atomic() in the serializer's create method to ensure that if any part of the order creation fails, nothing gets saved to the database.
  • Permission Checks: The IsAuthenticated permission ensures only logged-in users can place orders. You can add more granular permissions if needed (e.g., only admins can update order status).
  • Frontend Payload: When creating an order, your frontend should send a payload like this:
    {
      "items": [
        {"content_type": "food", "object_id": 1, "quantity": 2},
        {"content_type": "drink", "object_id": 3, "quantity": 1}
      ]
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:48:15