Django ModelForm не может сохранить записи «многие ко многим», используя ModelForm и save_m2m - PullRequest
0 голосов
/ 26 октября 2018

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

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

Я нашел несколько разных ответов на этот вопрос, некоторые для 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)

Ответы [ 4 ]

0 голосов
/ 29 октября 2018

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

0 голосов
/ 27 октября 2018

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

0 голосов
/ 28 октября 2018

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

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

0 голосов
/ 26 октября 2018

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

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

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

...