Django管理表单发布后为空

2024-06-25 06:38:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有麻烦在一个管理表单中发布数据。一些字段在单击save按钮后变为空,而其他字段则不为空(inlines保留其数据)。请参阅图片以获得对问题的更好解释。在

输入一些数据: Before post 点击[保存]后。。。 After clicking on save 验证错误!(模型未保存)

我的ModelForm非常简单:我只是更改其中一个m2m模型字段的表单字段。在

class News(models.Model):
    departments = models.ManyToManyField(Department, blank=True, related_name='news', through='NewsDepartmentMembership')
    research_groups = models.ManyToManyField(Group, blank=True, related_name='news', through='NewsGroupMembership')
    related_news = models.ManyToManyField('self', blank=True, symmetrical=False)
    people_involved = models.ManyToManyField(Person, blank=True, related_name='news')

    title = models.CharField(_('Title'), max_length=255)
    slug = models.SlugField(_('Slug'), unique_for_date='pub_date',
                        help_text=_('A slug is a short name which uniquely identifies the news item for this day'), )
    excerpt = RichTextField(_('Excerpt'), blank=True)
    content = RichTextField(_('Content'), blank=True)

    is_published = models.BooleanField(_('Published'), default=False)
    pub_date = models.DateTimeField(_('Publication date'), default=datetime.datetime.now)
    is_feat = models.BooleanField(
        _('Featured'), default=False,
        help_text=_('Administrators may use this checkbox to promote news to the main news page')
    )

    published = PublishedNewsManager()
    objects = models.Manager()
    featured = FeaturedNewsManager()

class NewNewsForm(forms.ModelForm):
    class Meta:
        model = News

    related_news = forms.ModelMultipleChoiceField(
        queryset=News.objects.none(),
        required=False,
        widget=FilteredSelectMultiple(
            verbose_name=_('articles'),
            is_stacked=False,
        )
    )

    def __init__(self, user=None, *args, **kwargs):
        super(NewNewsForm, self).__init__(*args, **kwargs)
        if hasattr(user, 'is_superuser'):
            self.fields['related_news'].queryset = get_objects_for_user(user, ('news.change_news',)).filter(
                is_published__exact=True).order_by('pub_date')
        else:
            self.fields['related_news'].queryset = News.published.order_by('pub_date')
        if self.instance.pk:
            self.fields['related_news'].initial = self.instance.related_news.all()

    def save(self, commit=True):
        news = super(NewNewsForm, self).save(commit=False)
        if commit:
            news.save()

        if news.pk:
            news.related_news = self.cleaned_data['related_news']
            self.save_m2m()

        return news

ModelAdmin相当复杂,它继承了2个ModelAdmin。The 1st one来自django模型翻译包。我改编了来自here的第二个,只是为了执行跨内联表单集验证。它可以在其他软件包中正常工作(至少直到今天)。我只需要重写is_cross_valid方法来定义交叉内联验证

^{pr2}$

这是我的ModelAdminWithInlines,几乎与here相同:

class ModelAdminWithInlines(ModelAdmin):
    """
    Cross formsets validation. See https://stackoverflow.com/a/2746735
    """
    def is_cross_valid(self, request, form, formsets):
        """
        To perform cross-formset validation.
        Should be overriden in every inheriting class.
        """
        return True

    def add_view(self, request, form_url='', extra_context=None):
        """The 'add' admin view for this model."""
        model = self.model
        opts = model._meta

        if not self.has_add_permission(request):
            raise PermissionDenied

        ModelForm = self.get_form(request)
        formsets = []
        inline_instances = self.get_inline_instances(request, None)
        if request.method == 'POST':
            form = ModelForm(request.POST, request.FILES)
            if form.is_valid():
                new_object = self.save_form(request, form, change=False)
                form_validated = True
            else:
                form_validated = False
                new_object = self.model()
            prefixes = {}
            for FormSet, inline in zip(self.get_formsets(request), inline_instances):
                prefix = FormSet.get_default_prefix()
                prefixes[prefix] = prefixes.get(prefix, 0) + 1
                if prefixes[prefix] != 1 or not prefix:
                    prefix = "%s-%s" % (prefix, prefixes[prefix])
                formset = FormSet(data=request.POST, files=request.FILES,
                                  instance=new_object,
                                  save_as_new="_saveasnew" in request.POST,
                                  prefix=prefix, queryset=inline.queryset(request))
                formsets.append(formset)
            # if all_valid(formsets) and form_validated:
            formsets_validated = all_valid(formsets)
            cross_validated = self.is_cross_valid(request, form, formsets)
            if formsets_validated and form_validated and cross_validated:
                self.save_model(request, new_object, form, False)
                self.save_related(request, form, formsets, False)
                self.log_addition(request, new_object)
                return self.response_add(request, new_object)
        else:
            # Prepare the dict of initial data from the request.
            # We have to special-case M2Ms as a list of comma-separated PKs.
            initial = dict(request.GET.items())
            for k in initial:
                try:
                    f = opts.get_field(k)
                except FieldDoesNotExist:
                    continue
                if isinstance(f, ManyToManyField):
                    initial[k] = initial[k].split(",")
            if ModelForm.Meta.model._meta.module_name == 'news' and ModelForm.Meta.model._meta.object_name == 'News':
                form = ModelForm(initial=initial, user=request.user) # here I am injecting the user object into the form
                # just to be able to access the objects for this user
            else:
                form = ModelForm(initial=initial)
            prefixes = {}
            for FormSet, inline in zip(self.get_formsets(request), inline_instances):
                prefix = FormSet.get_default_prefix()
                prefixes[prefix] = prefixes.get(prefix, 0) + 1
                if prefixes[prefix] != 1 or not prefix:
                    prefix = "%s-%s" % (prefix, prefixes[prefix])
                formset = FormSet(instance=self.model(), prefix=prefix,
                                  queryset=inline.queryset(request))
                formsets.append(formset)

        adminForm = AdminForm(
            form, list(self.get_fieldsets(request)),
            self.get_prepopulated_fields(request),
            self.get_readonly_fields(request),
            model_admin=self)
        media = self.media + adminForm.media

        inline_admin_formsets = []
        for inline, formset in zip(inline_instances, formsets):
            fieldsets = list(inline.get_fieldsets(request))
            readonly = list(inline.get_readonly_fields(request))
            prepopulated = dict(inline.get_prepopulated_fields(request))
            inline_admin_formset = InlineAdminFormSet(
                inline, formset, fieldsets, prepopulated, readonly, model_admin=self
            )
            inline_admin_formsets.append(inline_admin_formset)
            media = media + inline_admin_formset.media

        context = {
            'title': _('Add %s') % force_text(opts.verbose_name),
            'adminform': adminForm,
            'is_popup': "_popup" in request.REQUEST,
            'media': media,
            'inline_admin_formsets': inline_admin_formsets,
            'errors': AdminErrorList(form, formsets),
            'app_label': opts.app_label,
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, form_url=form_url, add=True)

我真的不明白我问题的根源。有人能发现这个问题吗?在

谢谢!在

更新 正如@GarryCairns建议的那样,我试图从shell中保存一个对象。没问题。在

>>> n = News.objects.create(title_en='test', slug_en='test', content_en='test')
>>> n.id
4

更新2:

非翻译字段也为空:-/ Pre-savePost-validation

更新3:

>>> n = News()
>>> n
<News: >
>>> n.title_en = 'test'
>>> n.slug_en
>>> n.slug_en = 'test'
>>> n.content_en = 'blah blah'
>>> n.save()
>>> n.id
5

固定的

似乎这两种方法都是从init()中手动设置ModelMultipleChoiceField查询集,而NewsAdmin.formfield_用于多个()方法把整个表格数据弄乱了。。。在


Tags: selfformtruegetprefixmodelifis