How to access a variable in inherited class based views - django

I am wondering how to run a reality check to decide which template file to use. How do I access agency_count from AgencyFullView? What I currently have returns type object 'AgencyFullMixin' has no attribute 'agency_count'
class AgencyFullMixin(ContextMixin):
def get_context_data(self, pk, **kwargs):
context_data = super(AgencyFullMixin, self).get_context_data(**kwargs)
agency = Agencies.objects.filter(pk=pk)
context_data["agency"] = agency
agency_count = agency.count()
context_data["agency_count"] = agency_count
return context_data
class AgencyFullView(TemplateView, AgencyFullMixin):
if agency_count != 0: **<<<--- What to put here?**
template_name = 'community_information_database/agency_full.html'
else:
template_name = 'community_information_database/not_valid.html'
def get_context_data(self, **kwargs):
context_data = super(AgencyFullView, self).get_context_data(**kwargs)
return context_data

If you want to access agency_count in another method, then you'll have to set it as an attribute. You could do this in the dispatch method.
class AgencyFullMixin(ContextMixin):
def dispatch(self, request, *args, **kwargs):
agencies = Agencies.objects.filter(pk=self.kwargs['pk'])
self.agency_count = agencies.count()
return super(AgencyFullMixin, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
"""
Add the agency count to the context
"""
context = super(AgencyFullMixin, self).get_context_data(**kwargs)
context['agency_count'] = self.agency_count
return context
You can then access self.agency_count in other methods. To change the template name dynamically, you should override get_template_names.
class AgencyFullView(AgencyFullMixin, TemplateView):
def get_template_names(self):
if self.agency_count != 0:
template = 'community_information_database/agency_full.html'
else:
template = 'community_information_database/not_valid.html'
return [template] # nb get_template_names must return a list

Fixed: Here's the solution I am using:
class AgencyFullMixin(ContextMixin):
def get_context_data(self, pk, **kwargs):
context_data = super(AgencyFullMixin, self).get_context_data(**kwargs)
agency = Agencies.objects.filter(pk=pk)
context_data["agency"] = agency
agency_count = agency.count()
context_data["agency_count"] = agency_count
return context_data
class AgencyFullView(TemplateView, AgencyFullMixin):
def get_template_names(self, **kwargs):
agency = Agencies.objects.filter(pk=self.kwargs['pk']).filter(pk__isnull=False)
if agency:
return 'community_information_database/agency_full.html'
else:
return 'community_information_database/not_valid.html'
def get_context_data(self, **kwargs):
context_data = super(AgencyFullView, self).get_context_data(**kwargs)
return context_data

Related

Django : "break" a class based view with intermediate "return render" won't work

I use a CB ListView for displaying objects. I want to add a session variable based on another models' PK during the execution of my ListView:
views.py
class ProduitListView(LoginRequiredMixin, ListView):
model = Produit
context_object_name = "produits"
paginate_by = 10
template_name = 'products/produits.html'
ordering = ['-mageid', ]
def get_context_data(self, *args, **kwargs):
context = super(ProduitListView, self).get_context_data(
*args, **kwargs)
# used for incoming products (sourcing cf URLS)
supplier_pk = self.kwargs.get('pk', None)
if supplier_pk:
set_incoming_supplier(self.request, supplier_pk)
context['avail_warehouses'] = Warehouse.objects.all()
context['js_warehouses'] = serialize(
'json', Warehouse.objects.all(), fields=('code', 'id', ))
context['title'] = 'Produits'
return context
set_incoming_supplier (in another APP)
#login_required
def set_incoming_supplier(request, pk):
supplier = Supplier.objects.filter(pk=pk).first()
supp = SupplierSerializer(instance=supplier).data
rs = request.session
if 'income' in rs:
if 'cur_supplier' in rs['income']:
prev_supplier = rs['income']['cur_supplier']
if supp != prev_supplier:
return render(request, 'sourcing/alert_supplier_change.html',
{'prev_supplier': prev_supplier, 'cur_supplier': rs['income']['cur_supplier']})
rs['income'] = {'cur_supplier': supp}
I thought the return render(request, 'sourcing/alert_supplier_change... could "break" my ListView and render my alert page but it doesn't. ListView seems to continue and finally renders my ProduitListView page.
Why doesn't this work ?
Finally found a solution that consists in using get() method within my CBV. In it, I evaluate my supplier with set_incoming_supplier() that returns a context or None. According to this evaluation, I render either the regular template or my alert template.
ProduitListView(LoginRequiredMixin, ListView):
class ProduitListView(LoginRequiredMixin, ListView):
model = Produit
context_object_name = "produits"
paginate_by = 10
template_name = 'products/produits.html'
ordering = ['-mageid', ]
def get_context_data(self, *args, **kwargs):
context = super(ProduitListView, self).get_context_data(
*args, **kwargs)
context['avail_warehouses'] = Warehouse.objects.all()
context['js_warehouses'] = serialize(
'json', Warehouse.objects.all(), fields=('code', 'id', ))
context['title'] = 'Produits'
return context
def get(self, request, *args, **kwargs):
supplier_pk = self.kwargs.get('pk', None)
if supplier_pk:
context = set_incoming_supplier(self.request, supplier_pk)
if context:
return render(request, 'sourcing/alert_supplier_change.html', context)
return super().get(request, *args, **kwargs)
set_incoming_supplier()
def set_incoming_supplier(request, pk):
supplier = Supplier.objects.filter(pk=pk).first()
supp = SupplierSerializer(instance=supplier).data
rs = request.session
if 'income' in rs:
if 'cur_supplier' in rs['income']:
prev_supplier = rs['income']['cur_supplier']
if supp != prev_supplier:
return {'prev_supplier': prev_supplier, 'cur_supplier': supp}
rs['income'] = {'cur_supplier': supp}
Maybe not the best way but it works well.

Local variable 'cid' referenced before assignment

Im trying to add a payment method.
I also add Getway and Get Success Message.
Now I want to show success message with cid and name in my template page.
When I want to get context data, I got This Error.
** Local variable 'cid' referenced before assignment. **
My code:
class CheckoutSuccessView(View):
model = Transaction
template_name = 'success.html'
def get(self, request, *args, **kwargs):
# return render(request, self.template_name,{'transaction':transaction})
return HttpResponse('nothing to see')
def post(self, request, *args, **kwargs):
data = self.request.POST
try:
Transaction.objects.create(
name = data['value_a'],
cid = data['value_b'],
tran_id=data['tran_id'],
val_id=data['val_id'],
amount=data['amount'],
card_type=data['card_type'],
card_no=data['card_no'],
...
...
)
messages.success(request,'Payment Successfull')
name = data['value_a'],
cid = data['value_b'],
except:
messages.success(request,'Something Went Wrong')
context = {
'cid': cid,
'name' : name
}
return render(request, 'success.html', context)
You may miss block or put extra indentation.
Define it before try block.
You may try this:
class CheckoutSuccessView(View):
model = Transaction
template_name = 'success.html'
def get(self, request, *args, **kwargs):
# return render(request, self.template_name,{'transaction':transaction})
return HttpResponse('nothing to see')
def post(self, request, *args, **kwargs):
data = self.request.POST
name = data['value_a'],
cid = data['value_b'],
try:
Transaction.objects.create(
name = data['value_a'],
cid = data['value_b'],
tran_id=data['tran_id'],
val_id=data['val_id'],
amount=data['amount'],
card_type=data['card_type'],
card_no=data['card_no'],
...
...
)
messages.success(request,'Payment Successfull')
except:
messages.success(request,'Something Went Wrong')
context = {
'cid': cid,
'name' : name
}
return render(request, 'success.html', context)
I think you are using sslcommerz-lib for SSLCOMMERZ PAYMENT GATEWAY.

prepoluate a generec createview

i want that a form is prepoluate with data
my model:
TYPE = (("S",'Swing'),
("R","Rapide"))
class valuation(models.Model):
stock = models.ForeignKey("stock",on_delete=models.CASCADE,related_name='valuation',)
date = models.DateField(auto_created=True)
val_type = models.CharField(choices=TYPE, max_length=1,default='R')
user = models.ForeignKey("users.User", on_delete=models.CASCADE)
def __str__(self):
return f"{self.stock} - {self.date} - {self.val_type}"
my view:
class valuationCreateviewSwing(CreateView):
template_name = "evaluation/evaluation_create.html"
form_class = valuationModeform
def get_form_kwargs(self): # prepopulate form
kwargs = super(valuationCreateviewSwing, self).get_form_kwargs()
stck = get_object_or_404(stock, pk=self.kwargs['pk'])
kwargs['user'] = self.request.user
kwargs['val_type'] = "S"
kwargs['stock'] = stck
return kwargs
def get_context_data(self, **kwargs):
# we need to overwrite get_context_data
# to make sure that our formset is rendered
data = super().get_context_data(**kwargs)
if self.request.POST:
data["val_detail"] = ChildFormset1(self.request.POST)
else:
data["val_detail"] = ChildFormset1()
data.update({
"typeVal": "Swing",})
return data
def form_valid(self, form):
context = self.get_context_data()
val_detail_Swing = context["val_detail_Swing"]
self.object = form.save(commit=False)
# add data info neede about valuation model
self.object = form.save()
if val_detail_Swing.is_valid():
val_detail_Swing.instance = self.object
val_detail_Swing.save()
return super().form_valid(form)
def get_success_url(self):
return reverse("stock:stock-list")
I've a child form in my view (this part works ok):
ChildFormset1 = inlineformset_factory(
valuation, val_detail_Swing, form=valuationSwingModelform, can_delete=False)
I tried to use ge_for_kwargs but it seems not working as I've an error message :
init() got an unexpected keyword argument 'user'
You can use get_initial() method:
class valuationCreateviewSwing(CreateView):
template_name = "evaluation/evaluation_create.html"
form_class = valuationModeform
def get_initial(self):
query = self.request.GET
return {
'user': self.request.user.pk
'val_type': "S",
'stock': self.kwargs.get('pk')
}
...
Or you should override __init__() method and stay to use get_form_kwargs()
class valuationModeform(ModelForm):
class Meta:
model = Valuation
fields = '__all__'
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
val_type = kwargs('val_type', None)
stock = kwargs.pop('stock', None)
super().__init__(*args, **kwargs)
# assign initial values
self.fields['user'].initial = user
self.fields['val_type'].initial = val_type
self.fields['stock'].initial = stock

How can i pass one variable from a method to another method using same class?

How can i get variable qid in the 2nd method(form) from 1st method(contect_data).
now i getting error :
NameError: name 'tmp' is not defined
class AnswerView(FormView):
template_name = 'answer.html'
form_class = AnsForm
success_url='success'
def get_context_data(self, *args, **kwargs):
context = super(AnswerView,self).get_context_data(**kwargs)
qid = self.kwargs['qid']
print(qid)
self.qid=qid
q_obj = Quest.objects.get(id=qid)
context['question'] = q_obj
return context
def form_valid(self, form):
answ1 = form.cleaned_data['txta']
tmp = self.get_context_data().qid
obj4=Ans.objects.create(answer=answ1,status=0,questid=tmp)
obj4.save()
return super().form_valid(form)
Actually you can use self.kwargs['qid'] in form_valid also. So you can simply do this:
class AnswerView(FormView):
template_name = 'answer.html'
form_class = AnsForm
success_url='success'
def get_context_data(self, *args, **kwargs):
context = super(AnswerView,self).get_context_data(**kwargs)
qid = self.kwargs['qid']
q_obj = Quest.objects.get(id=qid)
context['question'] = q_obj
return context
def form_valid(self, form):
answ1 = form.cleaned_data['txta']
tmp = self.kwargs['qid']
obj4=Ans.objects.create(answer=answ1,status=0,questid=tmp)
obj4.save()
return super().form_valid(form)
One way of doing it would be by setting the variable qid as a data member of your class, although I'm not sure if that's ideal for your usecase. That way both the methods can access and modify it. Hope this solves your problem.

How can I pass a value to Django Form's init method from a view?

forms.py
class AddDuration(forms.Form):
def __init__(self, *args, **kwargs):
super(AddDuration, self).__init__(*args, **kwargs)
// set value to relates_to_choices
relates_to_choices = ????????????? // Something like self.choices
self.fields['duration'].choices = relates_to_choices
duration = forms.ChoiceField(required=True)
Now, I have a views.py file that has a class
class AddDurationView(FormView):
template_name = 'physician/add_duration.html'
form_class = AddDurationForm
Override the get_form_kwargs() method on the view.
views.py
class AddDurationView(FormView):
template_name = 'physician/add_duration.html'
form_class = AddDurationForm
def get_form_kwargs(self):
kwargs = super(AddDurationView, self).get_form_kwargs()
kwargs['duration_choices'] = (
('key1', 'display value 1'),
('key2', 'display value 2'),
)
return kwargs
forms.py
class AddDurationForm(forms.Form):
duration = forms.ChoiceField(required=True)
def __init__(self, duration_choices, *args, **kwargs):
super(AddDurationForm, self).__init__(*args, **kwargs)
// set value to duration_choices
self.fields['duration'].choices = duration_choices