Delete dropdown choice dynamically in Django - python

I need to hide a choice from a dropdown when a user is not authenticated.
class JobPostingListView(ListView):
form_class = JobPostingSearchForm
model = JobPosting
template_name = 'recruiters/job_posting_list.html'
def get_queryset(self):
form = self.form = self.form_class(self.request.GET)
......
def get_context_data(self, **kwargs):
context_data = super(JobPostingListView, self).get_context_data(**kwargs)
if not self.request.user.is_authenticated():
del self.form.fields['date_posted'].choices[1]
#Ok, It shows all except choice one
print self.form.fields['date_posted'].choices
#It doesn't work here because it shows all the choices
print self.form
context_data.update({
'form': self.form
})
return context_data
Note: The code is in the view because I don't have access to is_authenticated in the form.
The form shows all the choices and I want to hide the choice one.

A colleague helped me with that.
Inside get_queryset function.
Call form.fields['date_posted'].widget.choices.pop(1) in order to show the form without the choice one.
Call form.fields['date_posted'].choices.pop(1) to avoid the user modify the html and send a not valid choice in this case.
class JobPostingListView(ListView):
form_class = JobPostingSearchForm
model = JobPosting
template_name = 'recruiters/job_posting_list.html'
def get_queryset(self):
form = self.form = self.form_class(self.request.GET)
if not self.request.user.is_authenticated():
form.fields['date_posted'].choices.pop(1)
form.fields['date_posted'].widget.choices.pop(1)
...

Related

Django Forms - redirect after save

I have a detail view with 2 forms and here I provide code for only one of them. The form is located in a modal on user detailed view and I need to redirect the client to that detail view in which the form is. In the post method the request.GET['user'] returns the user id so I have everything needed to achieve this. I have tried the reverse and redirect, nothing worked I guess because of wrong code.
Should I provide a get_success_url() to do that? I think it will cause some problems because I can get user id only from post method.
class UserDetailView(LoginRequiredMixin, DetailView):
model = TbUser
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['entrance_rights_form'] = TbPeopleEntranceRightForm(
user=self.object, initial={'user': self.object})
return context
class TbPeopleEntranceRightFormView(FormView):
form_class = TbPeopleEntranceRightForm
template_name = 'users/create_entrance_permission_modal.html'
def post(self, request, *args, **kwargs):
print(request.POST['user']) # returns user id
entrance_rights_form = self.form_class(
user=None, data=request.POST)
terminal_permissions_form = TbTerminalPermissionForm(user=None)
if entrance_rights_form.is_valid():
entrance_rights_form.save()
return redirect('user-detail', args=(request.POST['user'],))
else:
return redirect('users-list')
urlpatterns = [
path('users-list/', UsersListView.as_view(), name='users-list'),
path('user-detail/<str:pk>/',
UserDetailView.as_view(), name='user-detail'),
path('tb-entrance-right-form/submit',
TbPeopleEntranceRightFormView.as_view(), name='tb-entrance-right-form'),
]
You don't need to pass the user id in the args as a tuple with redirect.
This should work:
if entrance_rights_form.is_valid():
entrance_rights_form.save()
user_id = request.POST['user'] # i suppose this returns user id as you mentioned
return redirect('user-detail', user_id)
EDIT:
you are not rendering the template inside the post method.
def post(self, request, *args, **kwargs):
print(request.POST['user']) # returns user id
entrance_rights_form = self.form_class(
user=None, data=request.POST)
terminal_permissions_form = TbTerminalPermissionForm(user=None)
if entrance_rights_form.is_valid():
entrance_rights_form.save()
return redirect('user-detail', request.POST['user'])
else:
return redirect('users-list')
return render(request, self.template_name, {'form': entrance_rights_form})

Django: passing a filtered Queryset to a ListView?

Using Django Class Based Views, I already have a ListView for Order objects, and I created a FormView to perform advanced searches on these orderers.
However, I'm not sure how to pass the filtered queryset of the FormView to the ListView.
Here is the code, with commented sections to explain the issue:
class OrdersListView(PermissionRequiredCanHandleOrders,
SelectRelatedMixin, PrefetchRelatedMixin,
ModelInContextMixin, SubSectionLastOrders,
RestaurantOrdersOnly,
ListView):
model = Order
paginator_class = DiggPaginator
paginate_by = 15
select_related = ('convive__user',)
prefetch_related = ('orderoperation_set',)
# will use the template named order_list.html
class OrdersAdvancedSearchView(PermissionRequiredCanHandleOrders,
ModelInContextMixin, SubSectionLastOrders,
RestaurantOrdersOnly, RestaurantMixin,
FormView):
model = Order
template_name = "orders/order_advanced_search.html"
form_class = OrderAdvancedSearchForm
def form_valid(self, form):
data = form.cleaned_data
queryset = Order.objects.all()
# Here, I'm using the form content to filter the queryset
# queryset = queryset.filter(some_attribute__in=data['stuff'])
# MY PAIN POINT IS HERE: what I'm supposed to do here ?
# my queryset is filtered, and I need to call OrderListView
# with it.
return super().form_valid(form)
You should use the ListView to filter the queryset with the GET request parameters. For this, add the form to your context and process it when getting the queryset:
def get_queryset(self):
self.form = OrderAdvancedSearchForm(data=self.request.GET or None)
if self.request.GET and form.is_valid():
# filter using the form's cleaned_data
queryset = super().get_queryset().filter(...)
else:
queryset = super().get_queryset()
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) # this calls self.get_queryset() which assigns self.form
context['form'] = self.form
return context
Now in your template you can just render the same form, except its method should be "GET" not "POST".

Django update field value after submit

I am new here and in Django. But I need your help :)
I have created a search page using ListView,FormMixin class and a simple FormView :
class Search(ListView,FormMixin):
template_name = "users/search.html"
form_class = SearchForm
def get_context_data(self,**kwargs):
"""To get results"""
def post(self, request, *args, **kwargs):
return SearchFormView.as_view()(request)
And
class SearchFormView(FormView):
template_name = 'users/search.html'
form_class = SearchForm
def get_success_url(self):
return reverse_lazy('users:search')
def get_initial(self):
if 'keySearch' in self.request.session:
for k in self.request.session.pop('keySearch'):
initial[k] = self.request.session.pop(k)
return initial
def form_valid(self, form):
print "Form valid"
request = form.cleaned_data
print "Search field {}".format(request)
for k,v in request.iteritems():
self.request.session[k]=v
self.request.session['keySearch']=request.keys()
return super(SearchFormView,self).form_valid(form)
But everytime, I submit the form, the "search" field is blanked. My aim is to keep in the field, the user input and display the keyword and the results of the search in the same time. I guess I am not using the get_initial method in a good way.
Moreover, I am sorry for this dirty code. I hope you have the solution and any comments would be great :)
Best regards
You need to assign the form values and send them again when you render the template, could try it like this if it's useful :
class SearchFormView(View):
template_name='users/search.html'
def get(self, request, *args, **kwargs):
valid_form = yourForm()
return render(request, self.template_name,{
"valid_form" : valid_form,
})

multiple forms in CreateView

I have two forms in my CreateView. Forms will be totally independent. It means they will be submitted independently. How can I achieve it in class based CreateView without overriding POST method?
class EventPage(CreateView):
template_name = 'event.html'
form_class = RegisterToEvent
def form_valid(self, form, **kwargs):
form.instance.event = Event.objects.get(id = self.kwargs['event_id'])
return super(EventPage, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(EventPage, self).get_context_data(**kwargs)
event = Event.objects.get(id = self.kwargs['event_id'])
participants = Participant.objects.filter(event_id = event.id)
context['participants'] = participants
context['event'] = event
context['upload_document_form'] = UploadDocument
return context
I think it is a good place to use Django formset
A formset is a layer of abstraction to work with multiple forms on the
same page
Another way is to parse submit button names from POST. For example:
if 'first_form_submit_name' in request.POST:
# do some stuff for first form
elif 'second_form_name' in request.POST:
# do some stuff for second one

Saving Django Formsets

The following code successfully adds a new ToolCalibration to my database, however it does not save the SerialFormset or PartFormset. I've been staring at this code trying to figure it out for quite some time now, so any and all help would be greatly appreciated. Thanks!
Forms.py
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from tool_cal.models import ToolCalibration, SerialNumber, PartNumber
class ToolForm(ModelForm):
class Meta:
model = ToolCalibration
SerialFormSet = inlineformset_factory(ToolCalibration, SerialNumber, can_delete=True)
PartFormSet = inlineformset_factory(ToolCalibration, PartNumber, can_delete=True)
Views.py
class ToolCreate(CreateView):
model = ToolCalibration
template_name = "create.html"
form_class = ToolForm
success_url = '/toolcal/success'
def get(self, request, *args, **kwargs):
"""
Handles GET requests and instantiates blank versions of the form
and its inline formsets.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
serial_form = SerialFormSet(prefix='serial')
part_form = PartFormSet(prefix='part')
return self.render_to_response(
self.get_context_data(form=form,
serial_form=serial_form,
part_form=part_form))
def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance and its inline
formsets with the passed POST variables and then checking them for
validity.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
serial_form = SerialFormSet(self.request.POST, prefix='serial')
part_form = PartFormSet(self.request.POST, prefix='part')
if (form.is_valid() and serial_form.is_valid() and
part_form.is_valid()):
return self.form_valid(form, serial_form, part_form)
else:
return self.form_invalid(form, serial_form, part_form)
def form_valid(self, form, serial_form, part_form):
"""
Called if all forms are valid. Creates a ToolCalibration instance along with
associated Serial and Parts and then redirects to a
success page.
"""
self.object = form.save()
serial_form.instance = self.object
serial_form.save()
part_form.instance = self.object
part_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, serial_form, part_form):
"""
Called if a form is invalid. Re-renders the context data with the
data-filled forms and errors.
"""
return self.render_to_response(
self.get_context_data(form=form,
serial_form=serial_form,
part_form=part_form))
Have you considered using django-extra-views? It contains a quick and easy CBV for dealing with InlineFormSets.
In addition to an InlineFormSetView and GenericInlineFormSetView, they've also got a CreateWithInlinesView that seems to be just what you want. Relevant docs here.
Example:
from extra_views import InlineFormSet, CreateWithInlinesView, UpdateWithInlinesView,
from extra_views.generic import GenericInlineFormSet
from tool_cal.models import ToolCalibration, SerialNumber, PartNumber
class SerialNumberInline(InlineFormSet):
model = SerialNumber
class PartNumberInline(GenericInlineFormSet):
model = PartNumber
class ToolCreateView(CreateWithInlinesView):
model = ToolCalibration
inlines = [SerialNumberInline, PartNumberInline]
def get_success_url(self):
return self.object.get_absolute_url()
Even if you don't want to use them, you could dig through the code and see how they handle it.

Categories

Resources