Django ModelForm не может сохранить записи типа "многие ко многим" с помощью ModelForm и save_m2m

Я новичок в Django и использую этот проект, чтобы изучить его. Я могу сохранить запись журнала, но связь "многие ко многим" не работает.

В этом представлении «создание» отображается правильная форма, включая поле с множественным выбором со всеми перечисленными криптовалютами (из модели криптографии). При отправке формы записи «многие-ко-многим» не сохраняются, но Журнал сохраняет отлично.

Я нашел кучу разных ответов на этот вопрос, некоторые относятся к python 2.7, но это самый простой метод, основанный на [документации Django] [1]. Любая помощь приветствуется.

Кроме того, отношения отлично работают в разделе администратора, поэтому я думаю, что это как-то связано с формами и / или просмотром и сохранением.

models.py

from django.db import models
from crypto.models import Crypto as CryptoModel

class Journal(models.Model):
    title = models.CharField(max_length=200, help_text='Journal Title', blank=False, null=False)
    content = models.TextField(max_length=2000, help_text='Journal Content (HTML OK)', blank=False, null=False)
    crypto_id = models.ManyToManyField(CryptoModel, blank=True)    
    created = models.DateTimeField(help_text='Created', auto_now_add=True, null=True)

    def __str__(self):
        return self.title  ## String for representing the Model object, usually name field or title

forms.py

from django.forms import ModelForm, ModelMultipleChoiceField, widgets
from journal.models import Journal as JournalModel
from crypto.models import Crypto as CryptoModel

class JournalForm(ModelForm):
    # select multiple items box
    cryptos = ModelMultipleChoiceField(widget=widgets.SelectMultiple(attrs = {'size': 30}), queryset=CryptoModel.objects.all())

    class Meta:
        model = JournalModel
        fields = [
            "title",
            "content",
        ]
        labels = {
            'title': 'Journal Title',
        }
        required = [
            "title", # same as model
            "content",  # same as model
        ]

views.py

from journal.forms import JournalForm
from django.utils import timezone
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from journal.models import Journal as JournalModel

    def Create(request):

        if request.method == "POST":
            form = JournalForm(request.POST) # form instance
            context = {'form': form} # if errors, keep the form data on next page load

            journal = form.save(commit=False)  # False needed for many-to-many
            journal.title = form.cleaned_data["title"]
            journal.content = form.cleaned_data["content"]
            journal.created = timezone.now()
            journal.save()  # save the form journal data, now we have a PK
            form.save_m2m()  # save the 'form' using ManytoMany method

            return HttpResponseRedirect('/journal/')

        form = JournalForm()
        context = {'form': form}

        return render(request, 'journal/create.html', context)

models.py 2

from django.db import models
from crypto.models import Crypto

class Journal(models.Model):
    title = models.CharField(max_length=200, help_text='Journal Title', blank=False, null=False)
    content = models.TextField(max_length=2000, help_text='Journal Content (HTML OK)', blank=False, null=False)
    crypto_id = models.ManyToManyField(Crypto, blank=True)    
    created = models.DateTimeField(help_text='Created', auto_now_add=True, null=True)

    def __str__(self):
        return self.title  ## String for representing the Model object, usually name field or title

forms.py 2

from django.forms import ModelForm, ModelMultipleChoiceField, widgets
from journal.models import Journal
from crypto.models import Crypto

class JournalForm(ModelForm):
    # select multiple items box
cryptos = ModelMultipleChoiceField(widget=widgets.SelectMultiple(attrs = {'size': 30}), queryset=Crypto.objects.all())

class Meta:
    model = JournalModel
    fields = [
        "title",
        "content",
        "cryptos",
    ]

views.py 2

from journal.forms import JournalForm
from django.utils import timezone
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from journal.models import Journal

def Create(request):

    if request.method == "POST":
        form = JournalForm(request.POST) # form instance
        context = {'form': form} # if errors, keep the form data on next page load

        journal = form.save(commit=False)  # False needed for many-to-many
        journal.created = timezone.now()
        journal.save()  # save the form journal data, now we have a PK

        journal.crypto_id.set(form.cleaned_data.get("cryptos")) # must be after "save"
        form.save_m2m()  # save the 'form' using ManytoMany method

        return HttpResponseRedirect('/journal/')

    form = JournalForm()
    context = {'form': form}

    return render(request, 'journal/create.html', context)
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
0
749
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы назвали поля своей модели и формы по-разному; Django не может знать, что они относятся к одному и тому же полю. Имя формы - crypos - правильное, вы должны переименовать поле вашей модели в это.

Кроме того, вы не указали поле в списке fields, поэтому Django даже не будет пытаться установить его в модели.

Обратите внимание, что, по вашему мнению, вам не нужно устанавливать заголовок или контент, это то, что form.save уже делает для вас.

Спасибо за ответ. Я внес предложенные вами изменения и разместил новый код как «****. Py 2». К сожалению, это не повлияло на результат, «Многие ко многим» не сохраняет, но отлично работает в разделе «Администратор». Есть другие идеи?

DBTales 27.10.2018 21:40
Ответ принят как подходящий

надеюсь, что это решит вашу проблему, но эта строка после сохранения экземпляра журнала journal.crypto_id.set (form.cleaned_data.get ("криптовалюта"))

Спасибо, Абдулла, добавив "journal.crypto_id.set (form.cleaned_data.get (" cryptos "))" в VIEW, проблема была устранена. Дополнительное примечание: это должно быть место после сохранения формы «журнала», но до сохранения многих ко многим.

Я обновил разделы "models.py 2", "forms.py 2" и "views.py 2" выше. Это рабочий код.

всегда пожалуйста. да, но это после journal.save (). и установить не нужно вызывать save () из формы.

Другие вопросы по теме