HttpResponseRedirect not working it shows error as 'context must be dict rather than response'
class FooterLinksView(TemplateView):
template_name = 'pages/footerlinks.html'
model = FooterLink
def get_context_data(self, **kwargs):
context = super(FooterLinksView,self).get_context_data(**kwargs)
string_name = self.kwargs['string']
obj = FooterLink.objects.get(link_url=string_name)
if obj.link_type == 'page':
try:
context['page_obj'] = obj
return context
except:
pass
else:
pass
print(obj.url_name)
return HttpResponseRedirect(str(obj.url_name))
get_context_data() is the method for return context, so it must return context object. If you want to redirect, do it in get().
like below
class FooterLinksView(TemplateView):
template_name = 'pages/footerlinks.html'
model = FooterLink
def get(self, request, *args, **kwargs):
string_name = self.kwargs['string']
obj = FooterLink.objects.get(link_url=string_name)
if obj.link_type != 'page':
return HttpResponseRedirect(str(obj.url_name))
else:
return super().get(*args, **kwargs)
# if python2
# return super(FooterLinksView, self).get(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super(FooterLinksView,self).get_context_data(**kwargs)
string_name = self.kwargs['string']
obj = FooterLink.objects.get(link_url=string_name)
if obj.link_type == 'page':
try:
context['page_obj'] = obj
return context
except:
pass
return context
or you can just use extra_context in TemplateView.
class FooterLinksView(TemplateView):
template_name = 'pages/footerlinks.html'
model = FooterLink
def get(self, request, *args, **kwargs):
string_name = self.kwargs['string']
obj = FooterLink.objects.get(link_url=string_name)
if obj.link_type != 'page':
try:
self.extra_context = {
'page_obj': obj
}
except:
pass
return HttpResponseRedirect(str(obj.url_name))
else:
return super().get(*args, **kwargs)
# if python2
# return super(FooterLinksView, self).get(*args, **kwargs)
You must always return a dict from your get_context_data function. If you want to redirect, you should override dispatch too:
class FooterLinksView(TemplateView):
...
def dispatch(self, request, *args, **kwargs):
string_name = self.kwargs['string']
obj = FooterLink.objects.get(link_url=string_name)
if obj.link_type != 'page':
return HttpResponseRedirect(str(obj.url_name))
return super(FooterLinksView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(FooterLinksView,self).get_context_data(**kwargs)
string_name = self.kwargs['string']
obj = FooterLink.objects.get(link_url=string_name)
context['page_obj'] = obj
return context
The code in your get_context_data is trying to retrieve a single object and passing it to the context dictionary. This functionality is already built-in the DetailView and seems to be a better fit here than the TemplateView.
from django.views.generic import DetailView
class FooterLinksView(DetailView):
model = FooterLink
template_name = 'pages/footerlinks.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
if self.object.link_type == 'page':
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
return HttpResponseRedirect(str(obj.url_name))
Now the only thing we need to add is how the FooterLink object is retrieved in the get_object method. If your link_url field of FooterLink is the primary key we can simply add pk_url_kwarg = 'link_url' in the top of the class. Otherwise you should use the slug_field and slug_url_kwarg.
class FooterLinksView(DetailView):
model = FooterLink
pk = 'link_url' # if link_url is the primary key
slug_field = 'link_url' # if link_url is not the primary key
slug_url_kwarg = 'string' # if link_url is not the primary key
template_name = 'pages/footerlinks.html'
...
Note: You should now use the object variable inside your template (instead of obj) or override yet another option: context_object_name.
class FooterLinksView(TemplateView):
template_name = 'pages/footerlinks.html'
model = FooterLink
def get(self, request, args, *kwargs):
context = self.get_context_data(**kwargs)
string_name = self.kwargs['string']
obj = get_object_or_404(FooterLink, link_url=string_name)
if obj.link_type == 'page':
context['page_obj'] = obj
return render(request, self.template_name, context)
else:
a = obj.url_name
return HttpResponseRedirect(a)
Related
There are several lines of code in the get method that are also used in the post method. How can I prevent code repetition in this view?
class ProductDetail(View):
def get(self, request, *args, **kwargs):
products = Product.objects.get(id=self.kwargs['pk'])
related_products = products.tags.similar_objects()[:4]
comments = Comment.objects.filter(is_reply=False, product_id=self.kwargs['pk'])
change = Chart.objects.filter(product_id=self.kwargs['pk'])
context = (
{'products': products, 'related_products': related_products, 'comments': comments,
'change': change})
return render(request, 'home/details.html', context)
def post(self, request, *args, **kwargs):
products = Product.objects.get(id=self.kwargs['pk'])
related_products = products.tags.similar_objects()[:4]
comments = Comment.objects.filter(is_reply=False, product_id=self.kwargs['pk'])
change = Chart.objects.filter(product_id=self.kwargs['pk'])
context = ({'products': products, 'related_products': related_products, 'comments': comments,
'change': change})
return render(request, 'home/details.html', context)
Does this work ?
class ProductDetail(View):
def dostuff(id):
self.products = Product.objects.get(id)
self.related_products = self.products.tags.similar_objects()[:4]
self.comments = Comment.objects.filter(is_reply=False, product_id=id)
self.change = Chart.objects.filter(product_id=id)
def get(self, request, *args, **kwargs):
dostuff(self.kwargs['pk'])
context = (
{'products': self.products, 'related_products': self.related_products, 'comments': self.comments,
'change': self.change})
return render(request, 'home/details.html', context)
def post(self, request, *args, **kwargs):
dostuff(self.kwargs['pk'])
context = ({'products': self.products, 'related_products': self.related_products, 'comments': self.comments,
'change': self.change})
return render(request, 'home/details.html', context)
You can simply use DetailView from DGCBV.
class ProductDetail(DetailView):
model = Product
template_name = 'home/details.html'
def post(self, request, *args, **kwargs):
return self.get(request, *args, **kwargs)
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
obj = context['products'] = context['product']
context['related_products'] = obj.tags.similar_objects()[:4]
context['comments'] = Comment.objects.filter(is_reply=False, produc=obj)
context['change'] = Chart.objects.filter(product=obj)
return context
if you rename you template to product_detail.html, you can remove template name attribute.
By the way: if you have only single product, why you named it "products" ?
I have a form ProductCreateForm. It is necessary to insert the form SpeciallyPriceForm inside it.
I have a view for ProductCreateForm. But I don’t know how to process SpeciallyPriceForm in it either.
class ProductsCreate(CreateView):
model = Product
form_class = ProductCreateForm
http_method_names = ['get', 'post']
def get_form_kwargs(self):
print('form')
kwargs = super(ProductsCreate, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get(self, request, *args, **kwargs):
self.object = None
...
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
self.object = None
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
product = form.save(commit=False)
product.user = self.request.user
product.save()
if self.request.is_ajax():
return JsonResponse({'success': True, 'location': location})
else:
return redirect(location)
def form_invalid(self, form):
....
upd.
class ProductsCreate(CreateView):
model = Product
form_class = ProductCreateForm
# template_name = 'products/product_form.html'
http_method_names = ['get', 'post']
def get_form_kwargs(self):
kwargs = super(ProductsCreate, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get_context_data(self, *args, **kwargs):
print('ok')
ctx=super(ProductsCreate, self).get_context_data(*args, **kwargs)
ctx['special_form'] = SpeciallyPriceForm()
return ctx
def get(self, request, *args, **kwargs):
self.object = None
if kwargs.get('slug'):
category = Category.objects.filter(slug=kwargs.get('slug')).first()
self.initial.update({'category': category})
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
self.object = None
form = self.get_form()
special_form = SpeciallyPriceForm(self.request.POST)
if form.is_valid() and special_form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
product = form.save(commit=False)
I need the template as
<form ... >
{{ form }} /*product_form
{{ formset }} /* specially_price_form
</form>
upd2
models
class Product(models.Model):
category = models.ForeignKey(
Category, related_name='product',
verbose_name=_('category'), on_delete=models.SET_NULL, null=True,
)
forms
self.fields['category'] = ModelMultipleChoiceField(queryset=provider.category.all())
def clean(self):
cleaned_data = super(ProductCreateForm, self).clean()
cd_category = cleaned_data.get('category')
views
form = self.get_form() #Error
I believe a formset is really to show the same form several times with different instances. What you want here is 2 forms. Add get_context data
def get_context_data(self, *args, **kwargs):
ctx=super().get_context_data(*args, **kwargs)
ctx['special_form'] = SpeciallyPriceForm()
return ctx
def form_valid(self, form):
special_form = SpeciallyPriceForm(self.request.POST)
if special_form.is_valid():
...
else: error code and return to screen
I have to implement several forms, therefore I need the combination of SingleObjectMixin, TemplateView. I always receive 'AssignAttendee' object has no attribute 'object'. Do you see why I get that error?
class AssignAttendee(SuccessMessageMixin, SingleObjectMixin, TemplateView):
template_name = 'attendees/front/assign_attendee.html'
success_message = _("Attendee has been successfully updated.")
def get_object(self):
return get_object_or_404(
Attendee,
ticket_reference=self.kwargs['ticket_reference'],
ticket_code=self.kwargs['ticket_code'],
)
#cached_property
def attendee_form(self):
return AssignAttendeeForm(
prefix='attendee',
data=self.request.POST or None,
# instance=self.attendee_contact,
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = {
'attendee_form': self.attendee_form,
}
The problem was that it was missing:
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
I am using django rest framework. I need to pass some extra context value in response but not getting extra_value in response.
class ResultRowView(generics.ListAPIView):
serializer_class = ResultRowSerializer
permission_classes = (AccountPermission, )
def get_serializer(self, *args, **kwargs):
context = {'extra_value': 5000}
return self.serializer_class(*args, context=context, **kwargs)
def get_queryset(self):
qs = ResultRow.objects.none()
pk = self.kwargs.get('pk', None)
try:
route = IncomingRoute.objects.get(account=self.request.user.account, pk=pk)
qs = route.app_module.rows.all()
except Exception, e:
print 'result_row_query: ', e
return qs
What is missing here ?
you can do this by overriding the list method like:
def list(self, request, *args, **kwargs):
response = super(ResultRowView, self).list(request, args, kwargs)
response.data[ 'extra_value' ] = 5000
return response
You will have to override the get_context_data method and then add context to it
def get_context_data(self, **kwargs):
context = super(PropertyListView, self).get_context_data(**kwargs)
context['some_key'] = some_value
return context
There are UpdateView and ModelForm, you need to pass a variable from view to form, here is view:
class EditBranchView(UpdateView):
model = Branches
template_name = 'branches/edit.html'
form_class=EditBranchForm
def get_context_data(self, *args, **kwargs):
context = super(EditBranchView, self).get_context_data(**kwargs)
if self.request.POST:
context['form'] = EditBranchForm(self.request.POST, instance=self.object, request=self.request, pk = self.kwargs['pk'])
context['phones_form'] = BranchPhonesFormSet(self.request.POST, instance=self.object)
else:
context['form'] = EditBranchForm(instance=self.object, request=self.request, pk = self.kwargs['pk'])
context['phones_form'] = BranchPhonesFormSet(instance=self.object)
return context
and my form:
class EditBranchForm(forms.ModelForm):
regions=forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)
owner = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=Profiles.objects.all())
def __init__(self, request, pk, *args, **kwargs):
super(EditBranchForm, self).__init__(*args, **kwargs)
self.pk = pk
self.request = request
self.fields['owner'].queryset = Profiles.objects.filter(pid=self.request.user.id)
self.fields['regions'].choices = self.request.user.organization.organizationtoregion_set.all().values_list('region__id', 'region__region_name')
but it give error:
init() takes at least 3 arguments (1 given)
How should I do it? Thanks
Your argument handling in EditBranchForm.__init__ is wrong. It should be something like this:
def __init__(self, *args, **kwargs):
self.pk = kwargs.pop('pk', None)
self.request = kwargs.pop('request')
super(EditBranchForm, self).__init__(*args, **kwargs)
user = request.user
self.fields['owner'].queryset = Profiles.objects.filter(pid=user.id)
self.fields['regions'].choices = user.organization \
.organizationtoregion_set.all() \
.values_list('region__id',
'region__region_name')