简体   繁体   中英

Django modelformset_factory save nothing

Created a set of forms for a simple model. When I am try to change the model object data in the form and save these changes in the database, the new data is not saved as a result, and a redirect to the form page with the same data occurs, although at least messages about the success or failure of the operation should be output. The terminal does not return any errors, it is written in the logs that the correct request was sent, the test server works without drops in normal mode. There is an opinion that the reason for this is a refusal to validate, but for what reason this happens and where exactly the error is hidden, it is not yet possible to understand.

And

When I clicked a "save" button, see this message in terminal (see below):

[25/Aug/2017 18:03:06] "GET /categories/?csrfmiddlewaretoken=igSZl3z8pcF9qRGaMts9hG3T9dyaIpVvAxB672R34bmKvGYd6pymjmtwyEgDHGg2&form-TOTAL_FORMS=6&form-INITIAL_FORMS=5&form-MIN_NUM_FORMS=0&form-MAX_NUM_FORMS=1000&form-0-id=1&form-0-name=fhdrhddh&form-0-order=0&form-1-id=2&form-1-name=gdegasf&form-1-order=6&form-2-id=3&form-2-name=dfdgbsbgsdgs&form-2-order=2&form-3-id=4&form-3-name=dbgsgbasedgbaedvg&form-3-order=3&form-4-id=5&form-4-name=dgfsdg3waesdvz&form-4-order=4&form-5-id=&form-5-name=&form-5-order=0 HTTP/1.1" 200 7502

models.py (categories app)

from django.db import models

# Create your models here.

class Category(models.Model):
    name = models.CharField(max_length = 30, db_index = True, unique = True, verbose_name = "Title")
    order = models.PositiveSmallIntegerField(default = 0, db_index = True, verbose_name = "Serial number")
    def __str__(self):
        return self.name
    class Meta:
        ordering = ["order", "name"]
        verbose_name = "category"
        verbose_name_plural = "categories"

views.py (categories app)

from django.views.generic.base import TemplateView
from django.forms.models import modelformset_factory
from django.shortcuts import redirect
from django.contrib import messages
from categories.models import Category
from generic.mixins import CategoryListMixin

CategoriesFormset = modelformset_factory(Category, can_delete=True, fields = '__all__', extra=1, max_num=None)

class CategoriesEdit(TemplateView, CategoryListMixin):
    template_name = "categories_edit.html"
    formset = None
    def get(self, request, *args, **kwargs):
        self.formset = CategoriesFormset()
        return super(CategoriesEdit, self).get(request, *args, **kwargs)
    def get_context_data(self, **kwargs):
        context = super(CategoriesEdit, self).get_context_data(**kwargs)
        context["formset"] = self.formset
        return context
    def post(self, request, *args, **kwargs):
        self.formset = CategoriesFormset(request.POST)
        if self.formset.is_valid():
            self.formset.save()
            messages.api.add_message(request, messages.SUCCESS, "List of categories successfully changed")
            return redirect("categories_edit")
        else:
            messages.api.add_message(request, messages.SUCCESS, "Something is wrong!!!")
            return super(CategoriesEdit, self).get(request, *args, **kwargs)

mixins.py

from django.views.generic.base import ContextMixin

class CategoryListMixin(ContextMixin):
    def get_context_data(self, **kwargs):
        context = super(CategoryListMixin, self).get_context_data(**kwargs)
        context["current_url"] = self.request.path
        return context

categories_edit.html (categories app)

{% extends "categories_base.html" %}
{% block title %} Categories {% endblock %}
{% block main %}
    {% include "generic/messages.html" %}
    {{ formset.errors }}
    <h2>Categories</h2>
    <form action="" method="post">
        {% include "generic/formset.html" %}
        <div class="submit-button"><input type="submit" value="Save"></div>
    </form>
{% endblock %}

formset.html (categories app)

{% csrf_token %}
{{ formset.management_form }}
<table class="form">
    <tr>
        <th></th>
        {% with form=formset|first %}
            {% for field in form.visible_fields %}
                <th>
                    {{ field.label }}
                    {% if field.help_text %}
                        <br>{{ field.help_text }}
                    {% endif %}
                </th>
            {% endfor %}
        {% endwith %}
    </tr>
    {% for form in formset %}
        <tr>
            <td>
                {% for field in form.hidden_fields %}
                    {{ field }}
                {% endfor %}
            </td>
            {% for field in form.visible_fields %}
                <td>
                    {% if field.errors.count > 0 %}
                        <div class="error-list">
                            {{ field.errors }}
                        </div>
                    {% endif %}
                    <div class="control">{{ field }}</div>
                </td>
            {% endfor %}
        </tr>
    {% endfor %}
</table>

messages.html (categories app)

{% if messages %}
    <div id="messages-list">
        {% for message in messages %}
            <p class="{{ message.tags }}">{{ message }}</p>
        {% endfor %}
    </div>
{% endif %}

urls.py (categories app)

from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from categories.views import CategoriesEdit

urlpatterns = [
    url(r'^$', login_required(CategoriesEdit.as_view()), name  = "categories_edit"),
]

settings.py (project)

"""
Django settings for t****** project.

Generated by 'django-admin startproject' using Django 1.10.6.

For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
"""

import os

BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '***************************************************'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'guestbook',
    'categories',
    'imagepool',
    'page',
    'main',
    'news',
    'shop',
    'django.contrib.sites',
    'django_comments',
    'easy_thumbnails',
    'taggit',
    'precise_bbcode',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 't******.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'tdkennel.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 't******l',
        'USER': 'p*******',
        'PASSWORD': '********',
        'HOST': '',
        'PORT': '5432',
    }
}

# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)

MEDIA_ROOT = os.path.join(BASE_DIR, 'upload')
MEDIA_URL = '/media/'

LOGIN_URL = "login"
LOGOUT_URL = "logout"

SITE_ID = 1

THUMBNAIL_BASEDIR = "thumbnails"
THUMBNAIL_BASEDIR = {"goods.Good.image": {"base": {"size": (200, 100)},},}

LOGIN_REDIRECT_URL = "main"

I recall that something similar happened to me. I ended up using a Form to create the Formset :

try:

from django.forms import ModelForm
from categories.models import Category
from django.forms.models import modelformset_factory

class CategoryForm(ModelForm):
    class Meta:
        model = Category
        fields = '__all__'

CategoryFormSet = modelformset_factory(Category, form=CategoryForm)

and use CategoryFormSet in CategoriesEdit

It's just a workaround, but hope this helps!

My inattention was my mistake. I wrote method="post" in the commented and concatenated part of the code of categories_edit.html (in my project) and forgot to write it in uncommented piece of code:

   {# <form method="post" action=""> #}
    <form method="" action="">
        {% include "generic/formset.html" %}
        {# {% csrf_token %} #}
        {# {{ formset.as_p }} #}
        <div class="submit-button"><input type="submit" value="Save"></div>
    </form>

But I confused the users, because wrote everything is correct in my Question, than delete concatenated part of the code and entered the correct piece of code:

    <form method="post" action="">
        {% include "generic/formset.html" %}
        {# {% csrf_token %} #}
        {# {{ formset.as_p }} #}
        <div class="submit-button"><input type="submit" value="Save"></div>
    </form>

I apologize to the users who responded to my question! Code working.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM