NoReverseMatch in Django after create Object - django

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

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.

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

Сreate a full copy of the object from UpdateView or from ListView in Django

I have Class Based views for my models. I want to create a full copy of the object and go to editing it. I would like to do this from UpdateView with a special button for copying, but it is a good option from the list of objects. How can I do this? Below is the code for one of the models.
My CreateView:
class CreateDealView(
CustomSuccessMessageDeal,
CustomPermissionRequired,
CreateView
):
model = Deal
template_name = 'db_visual/create_deal.html'
form_class = DealForm
permission_required = (
'db_visual.add_deal',
)
success_message = "Сделка %(pk)s успешно создана!"
def get_success_url(self):
url_kwargs = {'deal_id': self.object.id}
url_name = 'update_deal'
return reverse_lazy(url_name, kwargs=url_kwargs)
My UpdateView:
class UpdateDealView(
CustomSuccessMessageDeal,
CustomPermissionRequired,
UpdateView
):
model = Deal
pk_url_kwarg = 'deal_id'
template_name = 'db_visual/update_deal.html'
form_class = DealForm
success_message = "Сделка <a href='%(url)s'>%(id)s</a> " \
"успешно изменена!"
def get_success_url(self):
url_name = 'deals'
return reverse_lazy(url_name)
def get_success_message(self, cleaned_data):
return self.success_message % dict(
cleaned_data,
id=self.object.id,
url=reverse_lazy(
'update_deal',
kwargs={
'deal_id': self.object.id,
}
),
)
UPD: I wrote a view for create copy by id, but when I try redirect to UpdateView I get error:
My view:
def copy_deal(request, deal_id):
new_deal = Deal.objects.get(pk=deal_id)
new_deal.pk = None
new_deal.save()
return reverse_lazy(
'update_deal',
kwargs={'deal_id': new_deal.pk}
)
What's wrong with my reverse?
I changed
return reverse_lazy(
'update_deal',
kwargs={'deal_id': new_deal.pk}
) to
return HttpResponseRedirect(reverse(
'update_deal',
kwargs={'deal_id': new_deal.pk}
))

Passing extra variable with Django ListView

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)

how we save form through Class Based Generic View in django

i am using class based generic view in my Subject_En roll application
my view.py is
cc = 0
#login_required
def add_subject_enroll(request):
user = request.user
obj = StudentRegistration.objects.get(user=user)
print "obj.first_name",obj.first_name
first_name = obj.first_name
print "first_name",first_name
if obj.user:
print "object exist"
#form = Subject_EnrollForm(request.POST or None, initial={'student_name' : first_name})
#form = Subject_EnrollForm( initial={'student_name' : obj.first_name})
form = Subject_EnrollForm(request.POST or None, request.FILES or None)
form.fields["student_name"].initial = first_name
form.fields["birth_place"].initial = obj.birth_place
form.fields["gender"].initial = obj.gender
form.fields["phone"].initial = obj.phone
form.fields["email"].initial = obj.email
form.fields["phone"].initial = obj.phone
form.fields["nationality"].initial = obj.nationality
form.fields["religion"].initial = obj.religion
form.fields["blood_group"].initial = obj.blood_group
form.fields["nationality"].initial = obj.nationality
form.fields["nationality"].initial = obj.nationality
form.fields["nationality"].initial = obj.nationality
form.fields["nationality"].initial = obj.nationality
else:
print "object not found"
Subject_EnrollForm(request.POST or None, request.FILES or None)
if request.POST:
if form.is_valid():
a = form.save()
a.user = request.user
a.save()
#user.save()
messages.add_message(request,messages.SUCCESS, "your Profile was added")
#return HttpResponseRedirect('/app/all')
return HttpResponseRedirect('/')
args = {}
args.update(csrf(request))
args['form'] = form
context = RequestContext(request,
{'request': request,
'user': request.user,
'form': form})
return render_to_response('subject_enroll/add_subject_enroll.html', args, context)
class Subject_EnrollListView(ListView):
"""View to display all published and visible news entries."""
template_name = "subject_enroll/subject_enroll_list.html"
def get_queryset(self):
return Subject_Enroll.objects.all()
class DetailViewMixin(object):
"""Mixin to handle different DetailView variations."""
model = Subject_Enroll
#slug_field = 'translations__slug'
def get_queryset(self):
#return Subject_Enroll.objects.all()
return Subject_Enroll.objects.lang(self.request, False)
class Subject_EnrollDetailView(DetailViewMixin, DetailView):
def get_context_data(self, **kwargs):
context = super(Subject_EnrollDetailView, self).get_context_data(**kwargs)
context['subject_enrolls'] = Subject_Enroll.objects.all()
return context
class Subject_EnrollUpdateView(UpdateView):
form_class = Subject_EnrollForm
model = Subject_Enroll
template_name = 'subject_enroll/subject_enroll_detail.html'
def get(self, request, **kwargs):
self.object = Subject_Enroll.objects.get(id=self.request.id)
form_class = self.get_form_class()
form = self.get_form(form_class)
context = self.get_context_data(object=self.object, form=form)
return self.render_to_response(context)
def get_object(self, queryset=None):
obj = Subject_Enroll.objects.get(id=self.kwargs['id'])
return obj
i try with pass form in context of Detilviewmixin
class DetailViewMixin(object):
"""Mixin to handle different DetailView variations."""
model = Subject_Enroll
#slug_field = 'translations__slug'
def get_context_data(self, **kwargs):
context = super(DetailViewMixin, self).get_context_data(**kwargs)
#context['form'] = Subject_EnrollForm
#context['form'] = Subject_EnrollForm()
return context
def get_queryset(self):
#return Subject_Enroll.objects.all()
return Subject_Enroll.objects.lang(self.request, False)
in that form are render on template but when i press save button so it can't save record
from this code i get all field access in "subject_enroll/subject_enroll_detail.html" like {{ object.student_name }}
{{ object.enroll_status }}
so it gives value of that field but now i want to edit record in subject_enroll_detail.html template like s
subject_enroll values "draft" to "submit" with click on some buttons in subject_enroll_detail.html template
i tried with form view and updateview but can't find solution
pls help!!!
Thanks in advance!!
from django.views.generic import UpdateView
class StudentRegistrationUpdateView(UpdateView):
model = StudentRegistration
form_class = Subject_EnrollForm #don't need if you are editing all the fields
template_name = 'subject_enroll/add_subject_enroll.html'
https://docs.djangoproject.com/en/1.7/ref/class-based-views/generic-editing/#updateview
in your urls.py
import StudentRegistrationUpdateView
in urls.py don't forget to include 'pk' like below, this determines which object to be updated
url(r'student/(?P<pk>\d+)/update/$', StudentRegistrationUpdateView.as_view(), name='student_registration_update'),