Closed ghost closed 7 years ago
Hi! In the post
method you have written you do not create the inline forms or call the forms_valid
method. Creating the inline forms with the appropriate methods will process the file data from the inline forms submitted in the request. It looks like you've used the wrong version of post
as the basis for your method.
Take a look at ProcessFormWithInlinesView.post. Your code would probably work fine if you didn't override post
but instead set instance.author in forms_valid().
You are right, I have used wrong post
method. I created ProcessFormWithInlinesViewMixin
which inherits from ProcessFormWithInlinesView
and override correct post
method:
models.py
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from extra_views import InlineFormSet, CreateWithInlinesView
from extra_views.advanced import ProcessFormWithInlinesView
from .models import Post, PostFile
from .forms import PostForm
class PostFileFormSet(InlineFormSet):
model = PostFile
fields = ['code']
max_num = 10
extra = 1
class ProcessFormWithInlinesViewMixin(ProcessFormWithInlinesView):
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
self.object = form.save(commit=False)
self.object.author = self.request.user
self.object.save()
form.save_m2m()
messages.success(self.request, 'Post was successfully created!')
form_validated = True
else:
messages.error(self.request, 'Oooops! Please correct the error below and try again!')
form_validated = False
inlines = self.construct_inlines()
if all_valid(inlines) and form_validated:
return self.forms_valid(form, inlines)
return self.forms_invalid(form, inlines)
class PostCreateView(ProcessFormWithInlinesViewMixin, CreateWithInlinesView):
model = Post
form_class = PostForm
inlines = [PostFileFormSet]
template_name = 'form_create.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(PostCreateView, self).dispatch(*args, **kwargs)
def get_success_url(self):
return self.object.get_absolute_url()
Now inline formsets work :) But another problem occurs. When I type wrong data into my form and I press submit button, I get this error:
'PostCreateView' object has no attribute 'object'
env/lib/python3.5/site-packages/extra_views/advanced.py in construct_inlines, line 68
def construct_inlines(self):
"""
Returns the inline formset instances
"""
inline_formsets = []
for inline_class in self.get_inlines():
inline_instance = inline_class(self.model, self.request, self.object, self.kwargs, self)
inline_formset = inline_instance.construct_formset()
inline_formsets.append(inline_formset)
return inline_formsets
When I type wrong data into form, then construct_inlines method tries to recreate inline formsets with typed wrong data, but object is not yet available to use (because it is CreateWithInlinesView) :( I need to override construct_inlines method too.
Thank you very much for your help.
Hi, that's happening because you're actually overriding the post
method of BaseUpdateWithInlinesView which sets self.object
. The code as you have written it will also create the Post object even if the inline data contains an error...are you sure you want to do that? I think the code below might be more straightforward, assuming self.object.author
does not need to be set in order to validate the inlines:
class PostCreateView(CreateWithInlinesView):
model = Post
form_class = PostForm
inlines = [PostFileFormSet]
template_name = 'form_create.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(PostCreateView, self).dispatch(*args, **kwargs)
def get_success_url(self):
return self.object.get_absolute_url()
def forms_valid(self, form, inlines):
"""
If the form and formsets are valid, save the associated models.
"""
self.object = form.save(commit=False)
self.object.author = self.request.user
self.object.save()
form.save_m2m()
messages.success(self.request, 'Post was successfully created!')
for formset in inlines:
formset.save()
return HttpResponseRedirect(self.get_success_url())
def forms_invalid(self, form, inlines):
"""
If the form or formsets are invalid, re-render the context data with the
data-filled form and formsets and errors.
"""
messages.error(self.request, 'Oooops! Please correct the error below and try again!')
return self.render_to_response(self.get_context_data(form=form, inlines=inlines))
Hi, thank you for your response! Your solution works perfectly! :) If you want you can see my simple blog here: http://91.189.34.115
Very flashy! :+1: Glad that fixed it.
Thanks! But what do you mean by "flashy"? Do you think it has too much animations? I have one more question to you, but I would like not to ask you here in this issue. Could you give me your email or mail me?
Hello!
I have troubles with uploading multiple files with inline formset. I want to write a post and attach to this post multiple text (.txt) files. I have two models: Post and related PostFile model:
models.py
forms.py
views.py
templates/form_create.html
Image in Post model is uploaded but code in PostFile model is NOT uploaded :( Could you help me ? Thanks in advance!