AttributeError: 'TestimonyForm' object has no attribute 'save' - django

Help needed. I have no idea what is error-ed in the line of code. The traceback points to the form.save() line.
#views.py
class TestimonyFormFunction(View):
form = TestimonyForm
template = 'variablized_form.html'
#method_decorator(login_required)
def get(self, request):
form = self.form_class(None)
return render(request, self.template, {'form':form})
def post(self, request):
if request.method == 'POST':
form = TestimonyForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return render(request, 'testimony_post.html', {'Testimony':Testimony})
else:
form = TestimonyForm()
return render(request, 'variablized_form.html', {'form': form})
#forms.py
class TestimonyForm(forms.Form):
body = forms.CharField(label='Details', widget=forms.Textarea)

Related

Converting Form Function to a Class Based View in a Django Project

I am trying to convert my Form which is laid out in a function to be in a class based view:
Here is what I have reach out.
Function:
def add_business_plan(request):
info = Info.objects.all()
if request.method == 'POST':
form = infoForm(request.POST)
if form.is_valid():
form.save()
business_name = form.cleaned_data.get('businessName')
info_id = form.instance.id
messages.success(request, f'PDF created for {business_name}!, No.({info_id})')
return render(request, 'businessplan/businessplan.html', {'form': form, 'successful_submit': True})
else:
form = infoForm()
print(form.errors)
return render(request, 'businessplan/businessplan.html',
{
'form': form,
'successful_submit': False,
"Info": info
}
)
here is form
class infoForm(forms.ModelForm):
class Meta:
model = Info
fields = [
'businessName',
]
widgets = {
'problem_summary': RichTextFormField(),
}
You may try the following:
class AddBusinessPlan(View):
template_name = 'businessplan/businessplan.html'
form_class = infoForm
def get(self, request, *args, **kwargs):
form = self.form_class
print(form.errors)
return render(request, template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
business_name = form.cleaned_data.get('businessName')
info_id = form.instance.id
messages.success(request, f'PDF created for {business_name}!, No.({info_id})')
return render(request, self.template_name, {'form': form, 'successful_submit': True})
else:
return render(request, self.template_name, {'form': form})

converting CBV to FBV

I am trying to change all my Function Based View to Class based view, i’ve been fairly successful except for this view, it’s a detail view that contains paystack payment gateway. Any help will be hugely appreciated.
def car_rent_detail_view(request, pk):
object = get_object_or_404(CarRent, id=pk)
paystack = PaystackAccount(
settings.PAYSTACK_EMAIL,
settings.PAYSTACK_PUBLIC_KEY,
object.total_cost
)
context = {'object': object, 'pk_public': settings.PAYSTACK_PUBLIC_KEY, 'currency': 'NGN', 'paystack': paystack,
}
if request.method == 'POST':
if paystack.verify_transaction(request.POST['reference']):
messages.success(request, "payment successfull")
…
car_rented.save()
…
rent_activation.save()
messages.success(request, "Rent successfully updated")
return render(request, 'app/CarRent_detail.html', context=context)
I will like to convert the CBV below to FBV so i can add payment functionality to it.
class ContestantDetail(DetailView, FormMixin):
model = Contestant
context_object_name = 'contestants'
template_name = 'contest/contestant_detail.html'
form_class = VoteForm
def get_success_url(self):
return reverse('contest:contestant-detail', kwargs={'pk': self.object.pk})
def get_context_data(self, *args, **kwargs):
context = super(ContestantDetail, self).get_context_data(*args, **kwargs)
context['vote_contestant'] = Contestant.objects.get(pk=self.kwargs.get('pk'))
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
self.object = self.get_object()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form, *args, **kwargs):
contestant = Contestant.objects.get(pk=self.kwargs['pk'])
...
contestant.save()
messages.success(self.request, f'You have successfully casted {vote_count} vote.')
return super().form_valid(form)
The Class based View above can be converted to a Function based view as demonstrated below.
def contestant_detail_view(request, pk):
get_object_or_404(Contestant, pk=pk)
form = VoteForm()
context = {'contestants': get_object_or_404(Contestant, pk=pk),
'vote_contestant': Contestant.objects.get(pk=pk),
'form': form}
if request.method == 'POST':
form = VoteForm(request.POST)
if form.is_valid():
con = Contestant.objects.get(pk=pk)
...
con.save()
else:
form = VoteForm()
return render(request, 'contest/contestant_detail.html', context)

Ajax in function based view

I've come a cross a lot of tutorials regarding how to setup a class based view for ajax. Example:
class JoinFormView(FormView):
form_class = JoinForm
template_name = 'forms/ajax.html'
success_url = '/form-success/'
def form_valid(self, form):
response = super(JoinFormView, self).form_valid(form)
if self.request.is_ajax():
print(form.cleaned_data)
data = {
'message': "Successfully submitted form data."
}
return JsonResponse(data)
else:
return response
I'm wondering how would insert the required code for ajax into this function based view. Does the code required depend on whether or not I want to pull from or write to the db asynchronously?
def my_func_view(request):
template = 'accounts/profile.html'
form = Form123(request.POST or None)
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=True)
return redirect('/accounts/profile/')
else:
messages.error(request, 'There was an error.')
context = {'form': form,}
return render(request, template, context)
else:
context = {'form': form,}
return render(request, template, context)
Thanks for your help!
you do the same thing for the function based view too..
from django.http import JsonResponse
def my_func_view(request):
template = 'accounts/profile.html'
form = Form123(request.POST or None)
if request.is_ajax():
if form.is_valid():
instance = form.save(commit=True)
return JsonResponse({'status':'data'})
else:
messages.error(request, 'There was an error.')
return JsonResponse({'status':'data'})
else:
context = {'form': form,}
return render(request, template, context)

Django: Redirect to Detail View after Creation

I'd like to redirect to a detail view after I successfully submitted a form and created the object.
My view.py
class ObjectCreateView(CreateView):
model = Object
form_class = ObjectCreateForm
template_name = 'frontend/base/object_create.html'
def get(self, request, *args, **kwargs):
form = ForecastConfigurationCreateForm()
form.fields['status'] = ModelChoiceField(queryset=ObjectStatus.get_object_status_list(self))
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
self.fcc_form = form.save(commit=True)
messages.add_message(self.request, messages.INFO, 'Good job!')
return render_to_response(reverse(viewname='object_detail', kwargs={'uuid': self.fcc_form.uuid}))
else:
messages.add_message(self.request, messages.ERROR, 'Error!')
return render(request, self.template_name, {'form': form})
The error message is:
TemplateDoesNotExist at /object_create/
/object_detail/3a3d6279-1531-45d4-9ba9-b691886facf4/
And the URL that's calling is:
http://test.com:8000/object_create/?next=/object_detail/a5b2a693-6f90-4b98-b9a2-fc2fe6a90995/
what I want it to be is
http://test.com:8000/object_detail/a5b2a693-6f90-4b98-b9a2-fc2fe6a90995/
Thanks!
Instead of trying to render the page, use HttpResponseRedirect instead:
class ObjectCreateView(CreateView):
...
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
self.fcc_form = form.save(commit=True)
messages.add_message(self.request, messages.INFO, 'Good job!')
return HttpResponseRedirect(reverse('object_detail', kwargs={'uuid': self.fcc_form.uuid}))
else:
messages.add_message(self.request, messages.ERROR, 'Error!')
return render(request, self.template_name, {'form': form})
just stumbled across the answer. The return should be:
return redirect(reverse('object_detail', kwargs={'uuid': self.fcc_form.uuid}))

Django FBVs to CBVs

I'm refactoring my code and change all FBVs to CBVs. But one of them isn't look pretty well. So I'm asking for right CBVs for my example.
Here my FBVs
#login_required
def profile(request, username):
user_main = get_object_or_404(User, username=username)
user_profile = UserProfile.objects.get_or_create(user=user_main)[0]
form = UserProfileForm({'website': user_profile.website, 'picture': user_profile.picture})
if request.method == 'POST' and request.user == user_main:
form = UserProfileForm(request.POST, request.FILES, instance=user_profile)
if form.is_valid():
form.save(commit=True)
return redirect(profile, username)
else:
print(form.errors)
context_dict = {'user_main': user_main, 'user_profile': user_profile, 'form': form}
return render(request, 'rango/profile.html', context=context_dict)
Here's what I'm got:
#method_decorator(login_required, name='dispatch')
class ProfileView(DetailView, FormMixin):
template_name = 'rango/profile.html'
context_object_name = 'user_main'
form_class = UserProfileForm
def get_object(self, queryset=None):
user_main = get_object_or_404(User, username=self.kwargs['username'])
return user_main
def get_context_data(self, **kwargs):
context = super(ProfileView, self).get_context_data(**kwargs)
context['user_profile'] = self.get_user_profile()
return context
def get_initial(self):
user_profile = self.get_user_profile()
return {'website': user_profile.website, 'picture': user_profile.picture}
def get_form_kwargs(self):
kwargs = super(ProfileView, self).get_form_kwargs()
kwargs['instance'] = self.get_user_profile()
return kwargs
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid and request.user == self.object:
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
profile = form.save(commit=True)
return redirect('profile', self.kwargs['username'])
def form_invalid(self, form):
print(form.errors)
return super(ProfileView, self).form_invalid(form)
def get_user_profile(self):
return UserProfile.objects.get_or_create(user=self.object)[0]
I guess my way to solve this task looks horrible. Please show me the right way to make this CBV looks better.