Может ли Django ModelForm сохранять несколько новых моделей при одной отправке?

Я изучаю Django и создаю сайт для сохранения и отображения предложений еды в кафетерии. У меня есть модель Meal и еще один FoodItem, где несколько FoodItem являются дочерними элементами Meal.

    class Meal(models.Model):

        date = models.DateField(default=datetime.date.today)


        BFAST = 0
        LUNCH = 1
        DIN = 2
        MEAL_TIME_CHOICES = [
            (BFAST, 'Breakfast'),
            (LUNCH, 'Lunch'),
            (DIN, 'Dinner'),
        ]

        meal_time = models.IntegerField(
            choices = MEAL_TIME_CHOICES,
            default = MEAL_TIME_CHOICES[0]
        )


    class FoodItem(models.Model):
        meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
        name = models.CharField(max_length=80)

Я хочу создать ModelForm, которая имеет несколько текстовых входов для FoodItems, чтобы несколько блюд могли быть сохранены и связаны с одним и тем же блюдом при одном отправлении формы.

Моя попытка сейчас позволяет мне отправлять только один продукт за раз.

class FoodItemForm(forms.ModelForm):
    class Meta:
        model = FoodItem
        fields = ('name',)

Любая помощь в выполнении этого правильным способом будет очень признательна!

Создайте приложение с именем menu:

|menu
├───migrations
|       ...
├───templates
│       detail.html
│       list.html
│   __init__.py
│   admin.py
│   apps.py
│   forms.py
│   models.py
│   tests.py
│   urls.py
│   views.py
|project <--- the name of your "project"
│   asgi.py
│   settings.py
│   urls.py
│   wsgi.py
│   __init__.py
│templates <--- not used
│db.sqlite3
│manage.py

Добавьте приложение menu к установленным приложениям:

project/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'menu.apps.MenuConfig',
]

project/urls.py (на уровне проекта)

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('menu.urls')),
]

menu/urls.py

from django.urls import path
from .views import list_view, detail_view

app_name = 'menu'
urlpatterns = [
    path('', list_view, name='list'),
    path('<pk>/', detail_view, name='detail'),
]

menu/models.py

import datetime
from django.db import models


class Meal(models.Model):

    BFAST = 0
    LUNCH = 1
    DIN = 2

    MEAL_TIME_CHOICES = [
        (BFAST, 'Breakfast'),
        (LUNCH, 'Lunch'),
        (DIN, 'Dinner'),
    ]

    meal_name = models.CharField(max_length=100)
    date = models.DateField(default=datetime.date.today)
    meal_time = models.IntegerField(choices=MEAL_TIME_CHOICES,default=0)

    def __str__(self):
        return self.meal_name


class FoodItem(models.Model):
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
    food_item = models.CharField(max_length=80)

    def __str__(self):
        return self.food_item

Убедитесь, что вы makemigrations и migrate.

menu/forms.py

from django import forms
from django.forms.models import modelformset_factory
from .models import Meal, FoodItem


MealFormset = modelformset_factory(FoodItem, fields=('food_item',),
                                   extra=5, can_delete=True)

menu/admin.py

from django.contrib import admin
from .models import Meal, FoodItem


class MealAdmin(admin.ModelAdmin):
    pass

class FoodAdmin(admin.ModelAdmin):
    pass

admin.site.register(Meal, MealAdmin)
admin.site.register(FoodItem, MealAdmin)

menu/views.py

from django.shortcuts import render, redirect
from .forms import MealFormset
from .models import Meal


def list_view(request):
    context = {
        'objects': Meal.objects.all(),
    }
    return render(request, 'list.html', context=context)

def detail_view(request, pk):
    instance = Meal.objects.get(pk=pk)
    formset = MealFormset(request.POST or None)
    context = {
        'object': instance,
        'formset': formset,
    }
    if request.method == 'POST':
        if formset.is_valid():
            food_items = formset.save(commit=False)
            if formset.deleted_forms:
                for obj in formset.deleted_forms:
                    obj.instance.delete()
            for food_item in food_items:
                food_item.meal = instance
                food_item.save()
            return redirect('menu:list')

    return render(request, 'detail.html', context=context)

menu/templates/list.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>List</title>
</head>
<body>

  <div style="margin: auto; width: 50%; border: 1px solid black; padding: 20px;">
    <a href="{% url 'admin:index' %}">Admin Panel</a>
    <h1>Meals</h1>
    {% for meal in objects %}
    <div>
      <a href="{% url 'menu:detail' meal.pk %}">{{ meal }}</a>
    </div>
    {% endfor %}
  </div>

</body>
</html>

menu/templates/detail.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Food Items</title>
</head>
<body>
  <div style="margin: auto; width: 50%; border: 1px solid black; padding: 20px;">
    <form method="POST">
      {% csrf_token %}
      {{ formset.management_form }}
      {% for field in formset %}
        <div style="padding: 5px 40px;">{{ field }}</div>
      {% endfor %}
      <input type="submit" value="Submit">
    </form>
  </div>
</body>
</html>

Может быть, это не точно то, что вы хотите, но иллюстрирует некоторые ключевые понятия (я думаю).

Вернуться на верх