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,
})
Related
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})
I have a update view:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
def dispatch(self, *args, **kwargs):
return super(GeneralUserUpdateView, self).dispatch(*args, **kwargs)
def post(self, request, pk, username):
self.pk = pk
self.username = username
self.gnu = GeneralUser.objects.get(pk=self.pk)
#form = self.form_class(request.POST, request.FILES)
return super(GeneralUserUpdateView, self).post(request, pk)
def form_valid(self, form, *args, **kwargs):
self.gnu.username = form.cleaned_data['username']
self.gnu.email = form.cleaned_data['email']
self.gnu.first_name = form.cleaned_data['first_name']
self.gnu.last_name = form.cleaned_data['last_name']
self.gnu.address = form.cleaned_data['address']
self.gnu.save()
return redirect("user_profile", self.pk, self.username)
Here in this view I want to pass a context like:
context['picture'] = GeneralUser.objects.get(pk=self.pk)
I did trying get_context_data but I cant access pk in there..
Am I doing the update right?? How can I pass that context in there??
You shouldn't be overriding post at all. All of that logic should happen in get_context_data.
In fact, none of your overrides are needed. Everything that you do in form_valid will be done already by the standard form save. And overriding dispatch just to call the superclass is pointless.
Your view should look like this only, with no overridden methods at all:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
context_object_name = 'picture'
(although it seems a little odd that you want to refer to an instance of GeneralUser as "picture").
Edit to redirect to a specific URL, you can define get_success_url:
def get_success_url(self):
return reverse("user_profile", self.kwargs['pk'], self.kwargs['username'])
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)
...
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.
I m new to django, I m writing a class-based view for a form.
The problem is, this form renders well, but when posting I get form invalid.
I am not sure what should I do to get default validators validate the form. There are two fields in the form. One is choice field, whose choices are set dynamically based on logged-in user. Another is CharField. There is no need of validation as CharField is free text and ChoiceField is based on user's data.
forms.py
class HomeForm(forms.Form):
phones= forms.ChoiceField(label='Select phone', choices = (), required=True)
message = forms.CharField(max_length=10, required=True)
def __init__(self, user, *args, **kwargs):
super(HomeForm, self).__init__(*args, **kwargs)
print >> sys.stderr, 'form init'
self.fields['phones'].choices = [(ids.id, ids.phone_model.short_name) for ids in GCM_RegId.objects.filter(user=user)]
def process(self, user):
cd = self.cleaned_data
regid_id = cd['phones'].value
gcm_regid = GCM_RegId.objects.filter(id=regid_id)
views.py
class HomeView(FormView):
template_name = "home.html"
form_class = HomeForm
success_url = 'home'
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if(form.is_bound):
print >> sys.stderr, "Form is Bound"
else:
print >> sys.stderr, "Form is NOT Bound"
if form.is_valid():
print >> sys.stderr, "Form Valid"
return self.form_valid(form)
else:
print >> sys.stderr, "Form NOT Valid"
return self.form_invalid(form, **kwargs)
def get_form(self, form_class):
form = HomeForm(self.request.user, {})
return form
def form_valid(self, form):
form.process(self.request.user)
print >> sys.stderr, "RegIdSubmitView form_valid"
return super(HomeView, self).form_valid(form)
I guess the problem is when you create the form instance, you forget to pass the request.POST data to your form class, the get_form method should be:
def get_form(self, form_class):
form = HomeForm(self.request.user, data=self.request.POST)
return form
Or, I think the better way for get_form is:
def get_form(self, form_class):
return form_class(self.request.user, **self.get_form_kwargs()
Check the the source code of get_form_kwargs method in django.views.generic.edit.FormMixin, it automatically handle the request's PUT/POST data and files for you.