I am trying to convert a function based view to a class based view. I've done it with the CreateView but the UpdateView is giving me grief. It won't take my update. I can get the view to take my update, but it doesn't save it.
Here's my function based view:
def update_task_update_view(request, pk):
task = Task.objects.get(id=pk)
form = TaskForm(request.POST or None, instance=task)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect("MyTasks:task_detail", pk=task.id)
context = {
"form": form,
"task": task
}
return render(request, "partials/task_form.html", context)
And here was my attempt at a Class Based View.
class UpdateTaskUpdateView(LoginRequiredMixin,UpdateView):
model = Task
form_class = TaskForm
template_name = 'partials/task_form.html'
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
task = form.save()
task.save()
return redirect("MyTasks:task_detail", pk=task.id)
else:
return render(request, "partials/task_form.html", {
"form":form
})
This function based view is working fine, no issues with it.
Thanks to an assist from FB...Travis Tucker....
I did this instead and it seems to be working fine...
class UpdateTaskUpdateView(LoginRequiredMixin,UpdateView):
model = Task
form_class = TaskForm
template_name = 'partials/task_form.html'
def form_valid(self, form):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
task = form.save()
task.save()
return redirect("MyTasks:task_detail", pk=task.id)
else:
return render(request, "partials/task_form.html", {
"form":form
})
Related
I have two views, PostCreateView and PostUpdateView. They both route through the same html template, post_form.html. I want to create a Copy button that only appears if I am accessing a record through PostUpdateView. Pressing the Copy button will create a new record pre-filled with all the data from record that I was just on.
PostCreateView code:
class PostCreateView(LoginRequiredMixin, FormView):
template_name = 'trucking/post_form.html'
form_class = RecordForm
def form_valid(self, form):
form.instance.author = self.request.user
obj = form.save(commit=False)
obj.save()
messages.success(self.request, f'RECORD: {obj.container_no} was saved')
return super().form_valid(form)
def get_success_url(self):
if self.request.POST.get('Save_Exit'):
return reverse('close')
elif self.request.POST.get('Save'):
return reverse('post-create')
else:
return reverse('database')
PostUpdateView code:
class PostUpdateView(LoginRequiredMixin, UpdateView):
form_class = RecordForm
model = Post
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
history = Post.objects.filter(id = self.object.id).first().history.all().reverse()
data['history'] = get_status_changes(history)
return data
# checks to make sure the user is logged in
def form_valid(self, form):
form.instance.author = self.request.user
obj = form.save(commit=False)
messages.success(self.request, f'RECORD: {obj.container_no} was updated')
return super().form_valid(form)
def get_success_url(self):
if self.request.POST.get('Save_Exit'):
return reverse('close')
# return render(self.request, 'trucking/email_close.html')
elif self.request.POST.get('Save'):
return reverse('post-update', kwargs={'pk': self.object.id})
else:
return reverse('database')
Based on this post I tried creating a view like so:
def copy(request):
post = Post.objects.get(pk = request.users.post.id)
my_form = RecordForm(instance = post)
return render(request, 'trucking/post_form.html', {'form': my_form})
However, I get an error saying 'WSGIRequest' object has no attribute 'users'. I think that's not the only issue with this approach.
Should it be a part of PostUpdateView, since it takes the form information from an existing record? Should it be part of PostCreateView since you take the preexisting info and fill out a new form with it? Should it be a new view altogether? Any help is appreciated
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)
I have my response form and view like this
class ResponseForm(ModelForm):
class Meta:
model = ResponseModel
exclude = ('author', 'title','submit_count')
# help_texts = {
# 'ans1': user.q1.value,
# }
#login_required
def ResponseFormView(request):
if request.method == "POST":
form = ResponseForm(request.POST)
if form.is_valid():
submission = form.save(commit=False)
submission.author = request.user
submission.save()
return render(request, 'thanks.html', {})
else:
form = ResponseForm()
return render(request, 'response_tem.html', {'form': form})
I want the help text for 'ans1' field to be the value of q1 field of request.user. How do I do it?
You can do it like this:
class ResponseForm(ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None) # popping user from known arguments
super(ResponseForm, self).__init__(*args, **kwargs)
if user:
self.fields['ans1'].help_text = "Help Text for {}".format(user.username)
class Meta:
model = ResponseModel
exclude = ('author', 'title','submit_count')
#login_required
def ResponseFormView(request):
if request.method == "POST":
form = ResponseForm(request.POST)
if form.is_valid():
submission = form.save(commit=False)
submission.author = request.user
submission.save()
return render(request, 'thanks.html', {})
else:
form = ResponseForm(user=request.user) # passing user as known argument
return render(request, 'response_tem.html', {'form': form})
Here, in the view I am passing the request.user as known argument when I am initiating Form Class's Object (marked with comment). Then in the Form, I am catching the user sent from view and updating the field's help text.
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)
I am trying to use an UpdateView in Django to update two forms simultaneously. I have the get method working properly, but when I submit the update, the post method creates a new instance of the forms. How can I grab the forms from the get method and update them without creating a new instance? Everything is redirecting fine and I am getting no errors.
class MotionStudyInstanceUpdateView(UpdateView):
model = MotionStudyInstance
fields = ['height', 'weight', 'skin_type_score', 'fitzpatrick_skin_type']
template_name = 'data/motionstudyinstance_update.html'
success_url = reverse_lazy('data:motion-studies')
def get_context_data(self, **kwargs):
pass
def get(self, request, **kwargs):
pk = self.kwargs['pk']
item = MotionStudyInstance.objects.get(id=pk)
general_info = item.general_info
form = MotionStudyInstanceForm(
initial={'height': item.height, 'weight': item.weight, 'skin_type_score': item.skin_type_score,
'fitzpatrick_skin_type': item.fitzpatrick_skin_type})
form_two = GeneralInfoForm(initial={'case_report_form_number': general_info.case_report_form_number,
'form_type': general_info.form_type,
'study_start_date': general_info.study_start_date,
'signed_consent': general_info.signed_consent,
'gender': general_info.gender,
'miscellaneous_notes': general_info.miscellaneous_notes,
'adverse_events': general_info.adverse_events})
return render(request, self.template_name, {'form': form, 'foreign_form': form_two})
def post(self, request, **kwargs):
if request.method == 'POST':
form = MotionStudyInstanceForm(request.POST)
foreign_form = GeneralInfoForm(request.POST)
if form.is_valid() and foreign_form.is_valid():
general_info = foreign_form.save()
user_form = form.save(commit=False)
user_form.general_info = general_info
user_form.save()
return redirect('data:motion-studies')
else:
form = MotionStudyInstanceForm()
return render(request, self.template_name, {'form': form})
forms.py
class MotionStudyInstanceForm(forms.ModelForm):
class Meta:
model = MotionStudyInstance
exclude = ('general_info',)
widgets = {
'validation_status': forms.HiddenInput(),
'author': forms.HiddenInput(),
'sibling': forms.HiddenInput()
}
class GeneralInfoForm(forms.ModelForm):
class Meta:
model = GeneralInfo
fields = '__all__'
widgets = {
'form_type': forms.HiddenInput(),
}
Looks like you should be using the instance parameter on the forms.
So you can update it on the post, and display it on the get
something like this:
def post(self, request, **kwargs):
pk = self.kwargs['pk']
item = MotionStudyInstance.objects.get(id=pk)
if request.method == 'POST':
form = MotionStudyInstanceForm(request.POST, instance=item)