How to call a function in django view.py - python

I need to call the function get_context_data in my VacanciesView.
Code views.py:
def VacanciesView(request):
navigate_results = Navigate.objects.all()
context_vac = { 'navigate_results': navigate_results}
get_context_data(self, **kwargs)
return render(request, 'main/vacancies.html', context_vac)
def get_context_data(self, **kwargs):
context = super(VacanciesView, self).get_context_data(**kwargs)
context['vacancies'] = sorted(get_vacancies(), key=lambda item: item["published_at"][:10])
return context
I try to do it by get_context_data(self, **kwargs), but it takes: name 'self' is not defined

You are using Function Based View (FBV), and the function you are trying to use is a method of Class Based View (CBW).
You can go one of two ways:
stay in FBV:
def VacanciesView(request):
navigate_results = Navigate.objects.all()
context = {'navigate_results': navigate_results, 'vacancies': sorted(get_vacancies(), key=lambda item: item["published_at"][:10])}
return render(request, 'main/vacancies.html', context)
switch to CBV:
class VacanciesView(TemplateView):
template_name = 'main/vacancies.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['navigate_results'] = Navigate.objects.all()
context['vacancies'] = sorted(get_vacancies(), key=lambda item: item["published_at"][:10])
return context

Related

How can I pass my filtered queryset from listview to another view that uses PDFTemplateView for printing?

I'm trying to print using wkhtmltopdf with a queryset from a django-filters filtered listview.
I can't use post because my list.html template is not a form.
filter_set = []
class IssueListView(TemplateListView):
def get_context_data(self, **kwargs):
context = super(IssueListView, self).get_context_data(**kwargs)
global filter_set
filter_set = []
for issue in context['object_list']:
filter_set.append(issue.pk)
return context
class IssuePDF(ReportTemplateView):
report_title = 'Complaints Register'
model = Issue
object_list = Issue.objects.all()
def get_context_data(self, **kwargs):
context = super(IssuePDF, self).get_context_data(**kwargs)
context['report_title'] = self.report_title
context['object_list'] = self.model.objects.all()
global filter_set
context['object_list'] = Issue.objects.filter(pk__in=filter_set)
return context
This works because I am currently using a global variable but the queryset changes everytime I print in the Production Server.
There are 2 ways to achieve that.
One is to store in session, like this:
class IssueListView(TemplateListView):
def get_context_data(self, **kwargs):
context = super(IssueListView, self).get_context_data(**kwargs)
self.request.session['filter_set'] = list(context['object_list'].values_list('pk', flat=True)) # This can be done get_queryset method as well
return context
And use it in IssuePDF:
class IssuePDF(ReportTemplateView):
report_title = 'Complaints Register'
model = Issue
object_list = Issue.objects.all()
def get_context_data(self, **kwargs):
context = super(IssuePDF, self).get_context_data(**kwargs)
context['report_title'] = self.report_title
filter_set = self.request.session.get('filter_set', None)
if filter_set:
context['object_list'] = Issue.objects.filter(pk__in=filter_set)
return context
Another way of achieving it is to pass the context as get parameter. Like this:
class IssueListView(TemplateListView):
def get_context_data(self, **kwargs):
context = super(IssueListView, self).get_context_data(**kwargs)
context['filter_set'] = list(context['object_list'].values_list('pk', flat=True))
return context
In template, update the print button/link like this:
<a href="{url 'app_name:print_view_url_name'}?filter_set={{ filter_set }}"
And use it in IssuePDF like this:
class IssuePDF(ReportTemplateView):
report_title = 'Complaints Register'
model = Issue
object_list = Issue.objects.all()
def get_context_data(self, **kwargs):
context = super(IssuePDF, self).get_context_data(**kwargs)
context['report_title'] = self.report_title
filter_set = self.request.GET.get('filter_set', None)
if filter_set:
context['object_list'] = Issue.objects.filter(pk__in=filter_set)
return context

Django CBV - set form class based on permissions?

I have created two forms in forms.py one form has less fields than the other.
what I would like to now do is get the current users permissions and set the form class of the CBV based on those perms.
below is my current view:
class EditCircuit(UpdateView):
model = Circuits
# if user_passes_test(lambda u: u.has_perm('config.edit_circuit')))
form_class = CircuitForm
# else
# form_class = CircuitFormRestricted
template_name = "sites/circuit_form.html"
#method_decorator(user_passes_test(lambda u: u.has_perm('config.edit_circuit')))
def dispatch(self, *args, **kwargs):
self.site_id = self.kwargs['site_id']
self.site = get_object_or_404(SiteData, pk=self.site_id)
return super(EditCircuit, self).dispatch(*args, **kwargs)
def get_success_url(self, **kwargs):
return reverse_lazy("sites:site_detail_circuits", args=(self.site_id,))
def form_valid(self, form):
form.instance.site_data = self.object.site_data
return super(EditCircuit, self).form_valid(form)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs()
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['SiteID']=self.site_id
context['SiteName']=self.site.location
context['FormType']='Edit'
context['active_circuits']='class="active"'
return context
You can override the get_form_class method.
def get_form_class(self):
if self.request.user.has_perm('config.edit_circuit'):
return CircuitForm
return CircuitFormRestricted
Also, it looks as though you don't need the get_form_kwargs definition, as it's not doing anything at the moment.
you can create your own mixin like this
class AuthorOnlyMixin(object):
def has_permissions(self):
return self.get_object().created_by == self.request.user
then use it like this
class EditViewClass(AuthorOnlyMixin, EditView):
def get_form_class(self):
if self.has_permissions():
return FormWithPermission
else:
return FormWithoutPermission

Django sqlite content in easy-pdf

Django version: 1.11.3
I have stored data in a sqlite database as I want to have displayed in a pdf. I use easy-pdf. I don't know how to parse the data without using render(). How do I do it with get_context_data(). Any suggestions?
This works:
def test(request):
all_organizations = Organization.objects.all()
all_tickets = Ticket.objects.all()
context = {'all_organizations': all_organizations, 'all_tickets': all_tickets}
return render(request, 'test/docs/examples/theme/test.html', context)
Don't know how to parse all_organizations and all_tickets for use in the easy-pdf:
class HelloPDFView(PDFTemplateView):
all_organizations = Organization.objects.all()
all_tickets = Ticket.objects.all()
context = {'all_organizations': all_organizations, 'all_tickets': all_tickets}
template_name = "test/docs/examples/theme/hello.html"
def get_context_data(self, **kwargs):
return super(HelloPDFView, self).get_context_data(
pagesize="A4",
title="Test",
**kwargs
)
def get_context_data(self, **kwargs):
context = super(HelloPDFView, self).get_context_data(**kwargs)
context['all_organizations'] = Organization.objects.all()
context['all_tickets'] = Ticket.objects.all()
context['pagesize']="A4"
context['title']= 'Test'
return context
try this, and in the template you can access the data using the key names like pagesize, title and all

Django 1.9 FormView never reach get_context_data

I have a FormView called LeagueTransferView based on a form LeagueTransferForm.
I'm trying to override get_context_data to add extra players to render in the template.
But get_context_data is never reached. It's working fine on other views like, DetailView, ListView,...
I'm missing something?
Below my configuration
View
class LeagueTransferView(FormView):
template_name = 'hockey/league/transfer_market.html'
form_class = LeagueTransferForm
success_url = ''
def get_context_data(self, **kwargs):
print('----NEVER REACHED----')
context = super(LeagueTransferView, self).get_context_data(**kwargs)
petitioner = get_object_or_404(Team, user=self.request.user.profile, league=self.kwargs['pk'])
context['players'] = Player.objects.filter(leagues=self.kwargs['pk']).exclude(teams=petitioner)
return context
def get(self, request, *args, **kwargs):
petitioner = get_object_or_404(Team, user=self.request.user.profile, league=self.kwargs['pk'])
form = self.form_class(initial={'league': self.kwargs['pk'], 'petitioner': petitioner})
form.fields['offered_player'].queryset = petitioner.players
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
transfer = form.save(commit=False)
team = Team.objects.filter(league=transfer.league, players__in=[transfer.requested_player])
if not team: # free agent
transfer.status = 1
messages.success(request, _('transfer succeeded'))
else:
print(team)
transfer.player_owner = team[0]
if transfer.petitioner.user is None: # bot team
transfer.status = 1
messages.success(request, _('transfer succeeded'))
else:
messages.success(request, _('transfer waiting for confirmation by player owner'))
transfer.save()
return HttpResponseRedirect(reverse('hockey_dashboard'))
petitioner = get_object_or_404(Team, user=self.request.user.profile, league=self.kwargs['pk'])
form.fields['offered_player'].queryset = petitioner.players
return render(request, self.template_name, {'form': form})
FORM
class LeagueTransferForm(forms.ModelForm):
class Meta:
model = Transfer
fields = ['league', 'requested_player', 'offered_player', 'player_owner', 'petitioner']
labels = {
'requested_player': _('Requested player'),
'offered_player': _('Offered player'),
}
widgets = {
'requested_player': forms.HiddenInput,
'league': forms.HiddenInput,
'player_owner': forms.HiddenInput,
'petitioner': forms.HiddenInput
}
Your code is never reaching get_context_data() because you have overridden the get() method and not calling the get_context_data() function there. You need to manually call the get_context_data() function at the time of passing context to render() in your code.
Instead of doing that, i would suggest you to try the below approach where instead of overrriding get() and returning your custom response, you only override what is necessary and let Django handle the rest.
class LeagueTransferView(FormView):
template_name = 'hockey/league/transfer_market.html'
form_class = LeagueTransferForm
success_url = ''
def get_context_data(self, **kwargs):
context = super(LeagueTransferView, self).get_context_data(**kwargs)
context['players'] = Player.objects.filter(leagues=self.kwargs['pk']).exclude(teams=self.petitioner)
return context
def get_initial(self):
initial = super(LeagueTransferView, self).get_initial()
initial['league'] = self.kwargs['pk'] # add custom data to initial
initial['petitioner'] = self.petitioner # add custom data to initial
return initial
def get_form(self, form_class=None):
form = super(LeagueTransferView, self).get_form(form_class)
# override the queryset
form.fields['offered_player'].queryset = self.petitioner.players
return form
def get(self, request, *args, **kwargs):
# only perform 1 query to get 'petitioner'
self.petitioner = get_object_or_404(Team, user=self.request.user.profile, league=self.kwargs['pk'])
return super(LeagueTransferView, self).get(request, *args, **kwargs)

Persist Django FormView Data

I have a FormView that generates a review of an object (which it is generically related to) and then links it to the object and saves it when the form is completed.
The issue I'm having is that I have no way to hold onto the data of the object I want to connect to. This means that I need to 'look it up' for context (template rendering) for valid processing (to do the linking) and for the success (to generate an appropriately reversed url.
Is there a better way to be binding the review to the object? Or better yet, is there a way to persist form data that I'm missing?
EDIT: Sorry the login decorator was on dispatch. I removed that method because SO was complaining about too much code and I didn't think it was relevant... I must have missed the decoratot
class ReviewCreate(FormView):
template_name = 'food/item_add_review.html'
form_class = ReviewForm
review_item = None
def get_context_data(self, **kwargs):
context = super(ReviewCreate, self).get_context_data(**kwargs)
item_modelname = self.kwargs.get('model')
item_model = apps.get_model('food',item_modelname)
review_item = get_object_or_404(item_model,pk=self.kwargs.get('pk'))
context['item'] = review_item
return context
def form_valid(self, form):
item_modelname = self.kwargs.get('model')
item_model = apps.get_model('food',item_modelname)
review_item = get_object_or_404(item_model,pk=self.kwargs.get('pk'))
r = form.save(commit=False)
r.content_object=review_item
r.save()
return super(ReviewCreate, self).form_valid(form)
def get_success_url(self):
item_modelname = self.kwargs.get('model')
item_model = apps.get_model('food',item_modelname)
review_item = get_object_or_404(item_model,pk=self.kwargs.get('pk'))
return reverse( 'pkitem', kwargs = {'pk': review_item.id, 'model':item_modelname},)
The view is an object right, so you just assign your values to instance variables, i e "to self" (this is thread-safe). Like this:
class ReviewCreate(FormView):
template_name = 'food/item_add_review.html'
form_class = ReviewForm
#method_decorator(login_required) # Use a class level mixin instead
def get_context_data(self, **kwargs):
return super(
ReviewCreate,
self
).get_context_data(
item=self.review_item,
**kwargs
)
def lookup_review_item(self):
self.item_modelname = self.kwargs.get('model')
item_model = apps.get_model('food', self.item_modelname)
self.review_item = get_object_or_404(
item_model,
pk=self.kwargs.get('pk')
)
def dispatch(self, request, *args, **kwargs):
# lookup performed here to be set for both GET and POST
self.lookup_review_item()
return super(ReviewCreate, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
r = form.save(commit=False)
r.content_object=self.review_item
r.save()
return super(ReviewCreate, self).form_valid(form)
def get_success_url(self):
return reverse(
'pkitem',
kwargs = {
'pk': self.review_item.id,
'model': self.item_modelname
},
)
The default form_valid() method for FormView redirects to the success url and reinitializes the form. You can make the form data persist by overriding form_valid():
def form_valid(self, form):
return super(YourFormView, self).get(form)
This will redirect to your success url with a (bounded) form having the posted data. The form is added to the context so you can use the data in your template or in your view as you wish.
(Django version 1.11.7)
The get_context_data should always return the context dictionary. It doesn't make sense to use the login_required decorator with it, because that means it might return a redirect response instead.
It would be better decorate the dispatch method instead. In your dispatch, you can set attributes on the instance.
class ReviewCreate(FormView):
#method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
self.item_modelname = self.kwargs.get('model')
self.item_model = apps.get_model('food',item_modelname)
self.review_item = get_object_or_404(item_model,pk=self.kwargs.get('pk'))
return super(ReviewCreate, self).dispatch(request, *args, **kwargs)
Then, in your other methods, you can access the attributes, for example:
def get_context_data(self, **kwargs):
context = super(ReviewCreate, self).get_context_data(**kwargs)
context['item'] = self.review_item
return context

Categories