Passing extra variable with Django ListView - django

Can't pass extra variable with listview
I tried adding another function and returning the value but it then doesn't return the main part.
class PostListView(ListView):
model = Post
template_name = 'blog/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 3
def get_context_data(self, **kwargs):
posting = []
for post in Post.objects.all():
post_words = post.content.split()
for word in post_words:
posting.append(word.lower())
mostused_word = []
for word in posting:
if len(mostused_word) == 0:
mostused_word.append({'daword': word, 'word_count': posting.count(word)})
else:
if posting.count(word) > mostused_word[0]['word_count']:
mostused_word[0] = {'daword': word, 'word_count': posting.count(word)}
context = {
'mostused_word': mostused_word[0]['daword'],
'mostused_word_count': mostused_word[0]['word_count'],
'postin': posting,
}
return context
I expect to pass both needed variables, not only one of them.

You need to call the super method.
def get_context_data(self, **kwargs):
...
context = {
'mostused_word': mostused_word[0]['daword'],
'mostused_word_count': mostused_word[0]['word_count'],
'postin': posting,
}
kwargs.update(context)
return super().get_context_data(**kwargs)

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.

Django form class and view class connected

Hi in my code(not written by me) i have django form class and views class. I dont know how this is connected each other. Can anyone tell me how this is connected? Also can any one please tell me how this messege : Credential is in use by {0} collections that are turned on and "
"{1} collections that are turned off. Be mindful that over-using " "credentials may result in collecting being rate limited by the " "social media API is displayed, i mean if i need to change the alignment of this text where i should change?
My code classes are :
from forms.py :
class CollectionTwitterSearch2Form(BaseCollectionForm):
incremental = forms.BooleanField(initial=True, required=False, label=INCREMENTAL_LABEL, help_text=INCREMENTAL_HELP)
def __init__(self, *args, **kwargs):
super(CollectionTwitterSearch2Form, self).__init__(*args, **kwargs)
self.helper.layout[0][5].extend(('incremental',))
if self.instance and self.instance.harvest_options:
harvest_options = json.loads(self.instance.harvest_options)
if "incremental" in harvest_options:
self.fields['incremental'].initial = harvest_options["incremental"]
def save(self, commit=True):
m = super(CollectionTwitterSearch2Form, self).save(commit=False)
m.harvest_type = Collection.TWITTER_SEARCH_2
harvest_options = {
"incremental": self.cleaned_data["incremental"],
}
m.harvest_options = json.dumps(harvest_options, sort_keys=True)
m.save()
return m
from views.py :
def _get_credential_use_map(credentials, harvest_type):
credential_use_map = {}
if harvest_type in Collection.RATE_LIMITED_HARVEST_TYPES:
for credential in credentials:
active_collections = 0
inactive_collections = 0
for collection in credential.collections.all():
if collection.is_on:
active_collections += 1
else:
inactive_collections += 1
if active_collections == 0 and inactive_collections == 0:
credential_use_map[credential.id] = ("", "")
else:
credential_use_map[credential.id] = ("warning",
"Credential is in use by {0} collections that are turned on and "
"{1} collections that are turned off. Be mindful that over-using "
"credentials may result in collecting being rate limited by the "
"social media API.".format(active_collections,
inactive_collections))
return credential_use_map
class CollectionCreateView(LoginRequiredMixin, CollectionSetOrSuperuserPermissionMixin, SuccessMessageMixin,
CreateView):
model = Collection
template_name = 'ui/collection_create.html'
def get_initial(self):
initial = super(CollectionCreateView, self).get_initial()
initial["collection_set"] = CollectionSet.objects.get(pk=self.kwargs["collection_set_pk"])
return initial
def get_context_data(self, **kwargs):
context = super(CollectionCreateView, self).get_context_data(**kwargs)
context["collection_set"] = CollectionSet.objects.get(pk=self.kwargs["collection_set_pk"])
harvest_type = self.kwargs["harvest_type"]
context["harvest_type_name"] = _get_harvest_type_name(harvest_type)
credentials = _get_credential_list(self.kwargs["collection_set_pk"], harvest_type)
context["credentials"] = credentials
context["credential_use_map"] = _get_credential_use_map(credentials, harvest_type)
context["platform"] = Collection.HARVEST_TYPES_TO_PLATFORM[self.kwargs["harvest_type"]]
return context
def get_form_kwargs(self):
kwargs = super(CollectionCreateView, self).get_form_kwargs()
kwargs["coll"] = self.kwargs["collection_set_pk"]
kwargs['credential_list'] = _get_credential_list(self.kwargs["collection_set_pk"], self.kwargs["harvest_type"])
return kwargs
def get_form_class(self):
return getattr(forms, _get_collection_form_class(self.kwargs["harvest_type"]))
def get_success_url(self):
return reverse('collection_detail', args=(self.object.pk,))
def get_success_message(self, cleaned_data):
if self.object.required_seed_count() != 0:
return "New collection added. You can now add seeds."
return "New collection added."
Full code is here in this git : https://github.com/gwu-libraries/sfm-ui/tree/master/sfm/ui
It would be great anyone can explain how these two classes and template is connected and how the messege is displayed
The CollectionCreateView class is conected to the Form using the function get_form_class, this function is called by default by the CreateView, in there you can see is calling _get_collection_form_class() and as an argument is passing self.kwargs['harvest_type'] this kwargs is comming from the url declaration. The _get_collection_form_class function is returning the CollectionTwitterSearch2Form when the harvest_type is something like TwitterSearch2. The template is given by the template_name = 'ui/collection_create.html' again this is the default vehaviour. And finally for the message this is using SuccessMessageMixin.

NoReverseMatch in Django after create Object

After creating an object without template, I am trying to return to the same list view but it sends the reverse match error.
This is my code:
Function to create an object from other model:
def pieza_fast_create(request, id_reporte):
template_name = "metalitec/reportes_detalle.html"
context_object_name = "obj"
reporte = Reporte.objects.get(id=id_reporte)
pieza=Pieza.objects.create(reporte=reporte, descripcion="PIEZA 1")
piezas = Pieza.objects.all()
return render(request, template_name, {'id_reporte':id_reporte,'reporte':reporte, 'piezas':piezas})
Current View:
class ReporteDetalleView(LoginRequiredMixin, generic.TemplateView):
model = Reporte
template_name = "metalitec/reportes_detalle.html"
context_object_name = "obj"
#login_url = "bases:login"
def get(self, request, *args, **kwargs):
id_reporte = kwargs['id_reporte']
reporte = Reporte.objects.filter(id=id_reporte)
piezas = Pieza.objects.filter(reporte__id=id_reporte)
return render(request, self.template_name, {'id_reporte':id_reporte, 'reporte':reporte, 'piezas':piezas})
URLs:
path('reportes/piezas/fast/<int:id_reporte>',pieza_fast_create, name='pieza_new_fast'),
path('reportes/detalle/<int:id_reporte>',ReporteDetalleView.as_view(), name='reporte_detalle'),
Error:
Reverse for 'pieza_new_fast' with arguments '('',)' not found. 1 pattern(s) tried: ['metalitec/reportes/piezas/fast/(?P<id_reporte>[0-9]+)$']
Rather than rendering the template metalitec/reportes_detalle.html again, it is better to redirect to that view ReporteDetalleView. You can try like this:
from django.shortcuts import redirect
def pieza_fast_create(request, id_reporte):
reporte = Reporte.objects.get(id=id_reporte)
pieza=Pieza.objects.create(reporte=reporte, descripcion="PIEZA 1")
return redirect('reporte_detalle', id_reporte=id_reporte)
Also, you can add some improvements to your code like this:
class ReporteDetalleView(LoginRequiredMixin, generic.TemplateView):
model = Reporte
template_name = "metalitec/reportes_detalle.html"
slug_url_kwarg = "id_reporte"
context_object_name = "reporte"
def get_context_data(self, **kwargs):
context = super(ReporteDetalleView, self).get_context_data(**kwargs)
reporte = context["reporte"]
context["piezas"] = Pieza.objects.filter(reporte=reporte)
context["id_reporte"] = self.kwargs["id_reporte"]
return context

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.

Django: Use a QuerySet in Function

I want to make some tournament matches in a DetailView. But I can't figure out how to make a query of all registrations context['regs'] and use the queryset in my function create_matches().
class KategorieDetail(DetailView):
model = Kategorie
context_object_name = 'kategorie'
def create_matches(regs):
red_corner = []
blue_corner = []
matches = []
# Separate the regs into both corners
i = 1
for reg in regs:
if i%2 == 1:
red_corner.append(reg)
else:
blue_corner.append(reg)
i += 1
# Create Match-Ups
while blue_corner:
match = {'red': red_corner.pop(), 'blue': blue_corner.pop()}
matches.append(match)
return matches
def get_context_data(self, **kwargs):
context = super(KategorieDetail, self).get_context_data(**kwargs)
kid = context['kategorie'].id
context['regs'] = Registrierung.objects.filter(kategorie=context['kategorie'].id)
context['regs_count'] = context['regs'].count()
context['matches'] = create_matches(context['regs'].values(), kid)
return context
In my HTML-View I can't display the matches. If I say {{matches}}, I get:
HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/events/"
I also don't get why I have to give the Kategorie_ID to the create_matches(regs) function.