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.
Related
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 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()
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
I've got one master detail relationship beteen Article and Section, and wish to allow a user to add sections on the same page before creating the Article.
It seems to work, but I'm also very new to Django, and wonder if I'm doing it right. There's a lot going on here, and I wonder if I'm overriding methods correctly, for example, and when I do, is the content correct?
A gold-standard way of doing it would be very appreciated!
class ArticleCreateView(LoginRequiredMixin,CreateView):
template_name = 'articles/article_add.html'
model = Article
form_class = ArticleForm
success_url = reverse_lazy('index')
SectionFormSet = inlineformset_factory(Article, Section, extra=2, can_delete=False, fields=('content',))
def get(self, request, *args, **kwargs):
print('get called on article create view')
self.object = None #what does this achieve?
return self.render_to_response(
self.get_context_data(form=self.get_form(),
section_form=self.SectionFormSet(),
))
def post(self, request, *args, **kwargs):
print('post called on article create view')
self.object = None
form = self.get_form()
section_form = self.SectionFormSet(self.request.POST)
if (form.is_valid() and section_form.is_valid()):
return self.form_valid(form, section_form)
else:
return self.form_invalid(form, section_form)
def form_valid(self, form, section_form):
form.instance.author = self.request.user
if section_form.is_valid():
print('section form is valid')
self.object = form.save()
section_form.instance = self.object
section_form.save()
return HttpResponseRedirect(self.success_url)
#return super().form_valid(form)
'''
return self.render_to_response( self.get_context_data(form=form,
section_form=section_form,
))
'''
def form_invalid(self, form, article_form):
return self.render_to_response(
self.get_context_data(form=form,
article_form=article_form))
I don't know if this is 100% correct, but it seems better than my previous code :
class ArticleCreateView(LoginRequiredMixin,CreateView):
template_name = 'articles/article_add.html'
form_class = ArticleForm
SectionFormSet = inlineformset_factory(Article, Section, extra=2, can_delete=False, fields=('content',))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
context['section_form'] = self.SectionFormSet(self.request.POST,instance=self.object)
else:
context['section_form'] = self.SectionFormSet(instance=self.object)
return context
def save_sections(self):
try:
context = self.get_context_data()
section_form = context['section_form']
if section_form.is_valid():
#section_form.instance = self.object
section_form.save()
except Exception as e:
print('failed to save section: ' + str(e))
def form_valid(self, form):
form.instance.author = self.request.user
response = super().form_valid(form) #save article form
self.save_sections()
return response
def get_success_url(self):
return reverse_lazy('index')
here's the update view (for completion), pretty much identical except it gets the instance of the article in the formset factory
class ArticleUpdateView(LoginRequiredMixin,UserPassesTestMixin,UpdateView):
template_name = 'articles/ArticleUpdate.html'
form_class = ArticleForm
model = Article
SectionFormSet = inlineformset_factory(Article, Section, extra=0, can_delete=False, fields=('content',))
def test_func(self):
article = self.get_object()
if self.request.user == article.author or self.request.user.is_superuser :
return True
else:
return False
def get_context_data(self, **kwargs):
print('get context data called update view')
context = super().get_context_data(**kwargs)
if self.request.POST:
context['section_form'] = self.SectionFormSet(self.request.POST,instance=self.object)
else:
context['section_form'] = self.SectionFormSet(instance=self.object)
return context
def save_sections(self):
print('save sections called update view')
try:
context = self.get_context_data()
section_form = context['section_form']
if section_form.is_valid():
# section_form.instance = self.object #if im passing instance in the factory, do I need it here to?
section_form.save()
except Exception as e:
print('failed to save section: ' + str(e))
def form_valid(self, form):
print('form valid called update view')
form.instance.author = self.request.user
response = super().form_valid(form) #save article form
self.save_sections()
return response
def get_success_url(self):
return reverse_lazy('index')
There is my view:
class SendTransfer(SingleObjectMixin, FormView):
model = BankAccount
form_class = SendTransferForm
template_name = 'dashboard/send_transfer.html'
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
return super(SendTransfer, self).dispatch(request, *args, **kwargs)
def get_object(self, queryset=None):
obj = super(SendTransfer, self).get_object(queryset)
if not obj.is_owner(self.request.user.citizen):
raise Http404
return obj
def form_valid(self, form):
data = form.cleaned_data
MoneyTransfer.objects.create(sender=self.object,
receiver=data['receiver'], # ModelChoiceField in the form
total=data['total'], # FloatField in the form, etc.
when=timezone.localtime(timezone.now()),
comment=data['comment'])
return redirect('AccountDetail', self.object.pk)
def form_invalid(self, form):
return render(self.request, self.template_name, self.get_context_data())
def get_form_kwargs(self):
return {'sender': BankAccount.objects.get(id=self.kwargs['pk']), 'user': self.request.user}
when form is submitting - I'm getting the same result as after get. Debugger says that clean() is not called but form_invalid is works. What is the problem?
You have overridden get_form_kwargs, and now you are no longer passing data to the form. Without data, the form is unbound, so will never be valid.
It would be better to call super() first, update the kwargs, then return them.
def get_form_kwargs(self):
kwargs = super(SendTransfer, self).get_form_kwargs()
kwargs['sender'] = BankAccount.objects.get(id=self.kwargs['pk']),
kwargs['user'] = self.request.user
return kwargs