converting CBV to FBV - django

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)

Related

How Do I Convert This Function Based View To An UpdateView?

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
})

How do I solve 'Model' object has no attribute 'object' for UpdateView for formset handling?

I am currently trying to get past numerous problems I've encountered with formset handling. Here is my latest code...In other issues it would seem that there might be an issue with formset and form_invalid(). I am trying to simply edit formset data that I have saved from a CreateView. It seems as if the data is presenting fine in the view after I save it from CreateView, but then I am not able to use this data or save it without changing anything. This issue seems eerily similar and I tried to use it to a degree but I couldn't get it to work either...Django passing form_valid inline formset context to get_context_data()
My View....
class UpdateTeamView(LoginRequiredMixin,UpdateView):
model = Team
form_class = UpdateTeamForm
template_name = 'update_team.html'
def get_context_data(self, **kwargs):
context = super(UpdateTeamView, self).get_context_data(**kwargs)
if self.request.POST:
context['player_form'] = PlayerFormSet(self.request.POST)
else:
context['player_form'] = PlayerFormSet(instance=self.object)
return context
def get_form_kwargs(self):
kwargs = super(UpdateTeamView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_object(self, queryset=None):
return get_object_or_404(Team, id=self.request.GET.get("dropdown"))
def get(self, request, *args, **kwargs):
dropdown=self.request.GET.get("dropdown")
if dropdown is not None:
if Team.objects.all().distinct():
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
else:
raise Http404
else:
messages.add_message(self.request, messages.INFO, 'Team is required.')
return HttpResponseRedirect(reverse('Company:update_team_by_name'))
def form_valid(self, form):
instance = form.save()
return super(UpdateTeamView, self).form_valid(form)
def form_invalid(self, form):
return self.render_to_response(
self.get_context_data(form=form,
))
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if "cancel" in request.POST:
return HttpResponseRedirect(reverse('Company:company_main_menu'))
else:
team_form = TeamForm(self.request.POST)
player_form = UpdateSavedNewCompanyContactFormSet(self.request.POST)
if player_form.is_valid():
print("works")
return HttpResponseRedirect(reverse('Team:main_menu'))
else:
player_form = UpdateSavedNewCompanyContactFormSet()
print("not working")
print(player_form.errors)
return super(UpdateTeamView, self).form_invalid(player_form)
After a lot of trial and error here was my solution....
def get_context_data(self, **kwargs):
context = super(UpdateTeamView, self).get_context_data(**kwargs)
if self.request.POST:
context['player_form'] = PlayerFormSet(self.request.POST, instance=self.object)
else:
context['player_form'] = PlayerFormSet(instance=self.object)
return context
def get_form_kwargs(self):
kwargs = super(UpdateTeamView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def get_object(self, queryset=None):
return get_object_or_404(UpdateTeamView, id=self.request.GET.get("dropdown"))
def form_valid(self, form):
data = self.get_context_data()
formset = data['company_contact_form']
if formset.is_valid():
self.object = form.save()
formset.instance = self.object
else:
print('formset invalid:', formset.errors)
instance = form.save()
def form_invalid(self, form, *args, **kwargs):
super().form_invalid()

Pagination in DetailView with context? [django]

I made comment and comments in Article(DetailView)
How can I make paginations this comments in DetailView.
I have tried many options but without succes...
VIEWS:
class ArticleDetailView(FormMixin, HitCountDetailView):
template_name = 'news/article_detail.html'
model = Article
count_hit = True
form_class = CommentForm
def get_success_url(self):
pk = self.kwargs["pk"]
slug = self.kwargs['slug']
return reverse_lazy('news:article_detail', kwargs={'pk': pk, 'slug': slug})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = ArticleComment.objects.filter(article_id=self.object.id).all()
context['comments_number'] = ArticleComment.objects.filter(article_id=self.object.id).count()
context['form'] = CommentForm()
return context
def form_valid(self, form):
form.instance.article = self.object
form.instance.author = self.request.user
form.save()
messages.success(request=self.request, message="KOMENTARZ ZOSTAŁ DODANY POPRAWNIE")
return super().form_valid(form)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
You can try like this.
from django.core.paginator import Paginator
qs = ArticleComment.objects.filter(article_id=self.object.id).all()
page = self.request.GET.get('page')
context['comments'] = Paginator(qs, 10).get_page(page)
return context

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.

Post request with DJango DetailView give error 'MyView' object has no attribute 'object'

I am trying to create an object with django DetailView. My code is like that.
class Detail(DetailView):
model = MyModel
template_name = 'mymodel_detail.html'
def get_context_data(self, **kwargs):
context = super(Detail, self).get_context_data(**kwargs)
context['form'] = DetailForm
return context
def post(self, request, *args, **kwargs):
form = DetailForm(request.POST, request.FILES)
if form.is_valid():
context['reply_form'] = DetailForm
self.object = super(Detail, self).get_object()
context['object'] = super(Detail, self).get_object()
return self.render_to_response(request=request, template=self.get_template_names(), context=context)
else:
context = context = super(Detail, self).get_context_data(**kwargs)
context['reply_form'] = form
self.object = super(Detail, self).get_object()
context['object'] = super(Detail, self).get_object()
return self.render_to_response(request=request, template=self.get_template_names(), context=context)
But here I am getting error that
'Detail' object has no attribute 'object'
I tried to assign object in context instance and with self as well. But nothing works.
What you are missing here is that you have to assign the object to the class or self before calling the get_context_data().
class Detail(DetailView):
model = MyModel
template_name = 'mymodel_detail.html'
def get_context_data(self, **kwargs):
context = super(Detail, self).get_context_data(**kwargs)
context['form'] = DetailForm
return context
def post(self, request, *args, **kwargs):
form = DetailForm(request.POST, request.FILES)
if form.is_valid():
# Write Your Logic here
self.object = self.get_object()
context = super(Detail, self).get_context_data(**kwargs)
context['form'] = DetailForm
return self.render_to_response(context=context)
else:
self.object = self.get_object()
context = super(Detail, self).get_context_data(**kwargs)
context['form'] = form
return self.render_to_response( context=context)
and in render_to_response() Just pass context. No other arguments.
Hope it will work for you.
This is how I implemented the code from Safrazs answer to make a reply option on my question model. I know this is an old question, but I hope that someone will find this useful.
class QuestionDetailView(generic.DetailView):
model = Question
template_name = 'forum/question.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = ReplyForm
return context
def post(self, request, *args, **kwargs):
form = ReplyForm(request.POST)
if form.is_valid():
reply = form.save(commit=False)
reply.creator = request.user
reply.question = self.get_object()
reply.save()
self.object = self.get_object()
context = context = super().get_context_data(**kwargs)
context['form'] = ReplyForm
return self.render_to_response(context=context)
else:
self.object = self.get_object()
context = super().get_context_data(**kwargs)
context['form'] = form
return self.render_to_response(context=context)
You are inheriting from the wrong generic view. You need to inherit from CreateView, like this:
class CreateModel(CreateView):
model = MyModel
template_name = 'mymodel_detail.html'
form_class = DetailForm
success_url = reverse('/thanks')
def form_valid(self, form):
# this method is called when the form
# is successfully validated
# if you need to do something with
# the database object, this is the place
# do not use it to redirect to a success page
# use the success_url for that
return super(CreateModel, self).form_valid(form)
You are calling super on the wrong class: they should be Detail, not MessageDetail. Also, you don't need the form code. Instead, use one of the generic editting views (CreateView, DeleteView, FormView, UpdateView). The DetailView is only for display purposes really. More detail on the generic views can be found at http://ccbv.co.uk/