I have this class that changes user password:
class PasswordsChangeView(PasswordChangeView):
from_class = PasswordChangingForm
success_url = reverse_lazy(
"base:password/passwordsuccess",
)
And I would like to insert User Avatar Img Path in context.
This Img is inside a UserComplement model.
When I create function views, it works doing:
#login_required
def password_success(request):
try:
obg = UserComplement.objects.get(pk=request.user.id)
context = {
"img_avatar": obg.avatar_image,
}
return render(request, "registration/passwordsuccess.html", context)
except UserComplement.DoesNotExist:
return render(request, "registration/passwordsuccess.html")
The problem is that I cannot get the userID in classviews to pass it through the context on success_url.
It was a lack of knowledge on how class based views work. The function get_context_data did the job well, returning the context.
class PasswordsChangeView(PasswordChangeView):
from_class = PasswordChangingForm
success_url = reverse_lazy(
"base:password/passwordsuccess",
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = UserComplement.objects.get(pk=self.request.user.id)
context["img_avatar"] = obj.avatar_image
return context
Related
I am new to Django and pretty lost on how to approach this problem.
Views.py:
class UserProfileDetailView(DetailView):
model = CustomUser
context_object_name = 'profile_detail'
template_name = 'user_profile_templates/profile_detail.html'
def get(self, request, pk, *args, **kwargs):
followers_var = request.user.motivators.all()
if len(followers_var) == 0:
is_following = False
for follower in followers_var:
if follower == request.user:
is_following = True
break
else:
is_following = False
number_of_followers = len(followers_var)
context = {
'number_of_followers': number_of_followers,
'is_following': is_following,
}
return render(request, 'user_profile_templates/profile_detail.html', context,)
So the problem is that I can't use context_object_name or 'object.var_name' in my template I guess that context that I defined in my get method is responsible for that. I've read somewhere that we should not use get() method in DetailView class, but I don't know what to do instead, should I use View and go from there? RequestContext? How would you refactor this whole class?
When you are using DetailView, you can put the code that deals with context in get_context_data:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
... # your code
context["number_of_followers"] = number_of_followers,
context["is_following"] = is_following,
Here is what I have currently.
views.py
class MultipleModelView(generic.TemplateView):
template_name = 'upload/home.html'
# #login_required(redirect_field_name='notloggedin.html')
def get_context_data(self, **kwargs):
if self.request.user.is_authenticated:
context = super(MultipleModelView, self).get_context_data(**kwargs)
context['jobs'] = Job.objects.filter(author=self.request.user).order_by('-created_at')
context['posts'] = devpost.objects.all().order_by('-created_at')
context['subcounter'] = SubCounter()
context['inprogcounter'] = InProgCounter()
context['fincounter'] = FinCounter()
return context
else:
context = super(MultipleModelView, self).get_context_data(**kwargs)
# context['jobs'] = Job.objects.filter(author=self.request.user).order_by('-created_at')
context['posts'] = devpost.objects.all().order_by('-created_at')
return context
class PostCreateView(LoginRequiredMixin,generic.CreateView):
model = Job
fields = ['patient_name', 'location']
def form_valid(self, form):
form.instance.author = self.request.user
id = randomStringDigits(5)
form.instance.identifier = id
sleepy.delay(id=id)
return super().form_valid(form)
The reason why it looks like this is because I have a page where I have multiple models on it.
The job model is updated in this file once it is created.
tasks.py
#shared_task
def sleepy(id=None):
MyModel = apps.get_model('upload','Job')
working_with = MyModel.objects.get(identifier=id)
working_with.status = "In Progress"
sleep(30)
working_with.status = "Finished"
return None
Essentially, once a user makes a post, it gets sent to an asynchronous task where I change an attribute in the model. The model is updated properly, but I want the detail view to change once the database updates. Is this possible?
I have the following class based view that I want to use to render a formset and validate it when it gets submitted through a post method:
The formset renders perfectly. When I submit the form I can read the formset and check it for errors. in the post method of this class -> errors = backorder_formset.errors
If I find any errors in the formset, I would like to render the view, but this time with the formset instance, that I read from POST.
When I call ctx = self.get_context_data() form within the post method of the class the following error gets raised from the call super(MissingProductsListView, self).get_context_data(*args, **kwargs):
'MissingProductsListView' object has no attribute 'object_list'
It seems like the superclass of Listview performs this call:queryset = kwargs.pop('object_list', self.object_list)
My question is why am I running in this error? and how could I render this formset with its errors messages to display it in the template after it was posted? I am using Django 1.9.9
class MissingProductsListView(generic.ListView):
template_name = 'dashboard/purchaseorder/missing_products.html'
context_object_name = 'backorders'
model = BackOrder
def post(self, request, *args, **kwargs):
backorder_formset = BackOrderFormset(request.POST)
errors = backorder_formset.errors
if backorder_formset.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
else:
ctx = self.get_context_data()
return self.render_to_response(ctx)
def accumulate_identical_products_from_backorders(self, back_order_list):
... some code
return sorted_accumulated_dict.values()
def get_context_data(self, *args, **kwargs):
ctx = super(MissingProductsListView, self).get_context_data(*args, **kwargs)
ctx['title'] = _("Missing Products")
if self.request.POST:
ctx['back_order_formset'] = BackOrderFormset(self.request.POST)
else:
accumulated_backorders_per_product = self.accumulate_identical_products_from_backorders(BackOrder.objects.all())
back_orders = BackOrderFormset(initial=[{'product_id': backorder_dict['product_id'],
'product': backorder_dict['title'],
'quantity': backorder_dict['quantity']} for backorder_dict in
accumulated_backorders_per_product])
ctx['back_order_formset'] = back_orders
return ctx
def get_queryset(self):
.. some code
return backorder_list
Look here:
class BaseListView(MultipleObjectMixin, View):
"""
A base view for displaying a list of objects.
"""
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'):
is_empty = not self.object_list.exists()
else:
is_empty = len(self.object_list) == 0
if is_empty:
raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") % {
'class_name': self.__class__.__name__,
})
context = self.get_context_data()
return self.render_to_response(context)
Basically - you missed this part in the POST handler:
self.object_list = self.get_queryset()
And to be honest - I am not quite sure if this is a good idea to add post to the generic ListView in django. It looks more like FormView - but I can be wrong here.
How can i pass the context data which is coming from a forms.py to my views class which is using generic detailView, i need to pass forms.py to my product detail page.
Here is the code for my view class
class ProductView(generic.DetailView):
model = Product
cart_product_form = CartAddProductForm()
context = {'cart_product_form': cart_product_form}
template_name = 'shopping/product.html'
query_pk_and_slug = True
Please let me know if this is incorrect
Override get_context_data, and add the form to the context before returning it.
class ProductView(generic.DetailView):
model = Product
template_name = 'shopping/product.html'
query_pk_and_slug = True
def get_context_data(self, **kwargs):
context = super(ProductView, self).get_context_data(**kwargs)
cart_product_form = CartAddProductForm()
context['cart_product_form'] = cart_product_form
return context
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)