Put forms.DateField parameter into view method - python

I have following problem:
In my forms.py i have following line in class:
date_from = forms.DateField(label='date', initial='1800-01-01', widget=SelectDateWidget(years=[y for y in range(1450,2050)]))
In template i can choose the concrete date.
This parameter i want to transfer to my view.py file to the following method:
def adv_search(request):
objects = None
if request.GET.get('key'):
form = AdvancedSearchForm(request.GET)
if form.is_valid():
repo = Repository()
objects = list(repo.find_objects(date__gt='2012-07-23'))
return render(request, 'templates/adv_search.html', {'form': form, 'objects': objects })
return render(request, 'templates/adv_search.html', {'form': AdvancedSearchForm(), 'objects': objects})
In objects = list(repo.find_objects(date__gt='2012-07-23')) i have date__gt with concrete Date.
How i can add to date__gt the date from form.Date.Field ?
Thanks.

It's in form.cleaned_data:
You can access it by doing:
objects = list(repo.find_objects(date__gt=form.cleaned_data['date_from']))
This is assuming that your form declaration looks something like:
class AdvancedSearchForm(forms.Form):
date_from = forms.DateField(...)
...

Related

Passing Form Data to View

I have the following view:
views.py
def PackingListView(request):
if request.method == "POST":
form = PackingListForm(request.POST)
if form.is_valid():
if 'preview' in request.POST:
request.session['data'] = form.cleaned_data
return redirect('myview')
....
I would like to take the data in form and pass it to this next view, and set the data variable equal to it. This was previously working, but once I added a foreign key into this form, the session no longer works as it is not serializable. What approach is the safest for me to take here?
views.py
class myview(View):
def get(self, request, *args, **kwargs):
data = request.session.pop('data', {})#this won't work now
pdf = render_to_pdf('packlist_preview.html', data)
return HttpResponse(pdf, content_type='application/pdf')
Also in case it is needed - here is the URL for myview
url(r'^myview/', views.myview.as_view(), name='myview'),
You should be able to serialize the data if you replace the model instance with its id.
data = form.cleaned_data
# remove object from data dict
related_object = data.pop('related_object')
# add in a reference
data['related_object_id'] = related_object.pk
# now you should be able to serialize object
request.session['data'] = data
Then in the next view, you can fetch the object from the database using its id
data = request.session.pop('data', {})
related_object_id = data.pop('related_object_id', None)
if related_object_id:
try:
data['related_object'] = RelatedObject.objects.get(pk=related_object_id)
except RelatedObject.DoesNotExist:
pass

BaseModelFormSet __init__() got an unexpected keyword argument

I am getting the above error when I have tried to convert my inline_formset to have at least the first row required. (please see here for the StackOverflow question)
My existing code is below:
#views.py
def application(request, job_id):
job = get_object_or_404(Job, pk=job_id)
#return 404 if job isn't yet published
if (job.pub_date>timezone.now() or job.close_date<timezone.now()):
return HttpResponseNotFound('<h1>Job not found</h1>')
#create all the inlineformsets (can_delete) set to false as will always be empty upon population
EducationInlineFormSet = inlineformset_factory(Applicant, Education, extra=1, can_delete=False)
QualificationInlineFormSet = inlineformset_factory(Applicant, Qualification, extra=1, can_delete=False)
EmploymentInlineFormSet = inlineformset_factory(Applicant, Employment, extra=1, can_delete=False)
if request.method == 'POST':
applicant = Applicant(job=job)
form = ApplicantForm(request.POST, instance=applicant)
bottom_form = ApplicantFormBottom(request.POST, instance=applicant)
education_formset = EducationInlineFormSet(request.POST, instance=applicant)
qualification_formset = QualificationInlineFormSet(request.POST, instance=applicant)
employment_formset = EmploymentInlineFormSet(request.POST, instance=applicant)
#check all of the forms and formsets are valid
if form.is_valid() and bottom_form.is_valid() and education_formset.is_valid() and qualification_formset.is_valid() and employment_formset.is_valid():
# save the model to database, directly from the form:
form.save()
bottom_form.save()
education_formset.save()
qualification_formset.save()
employment_formset.save()
return render(request, 'jobs/success.html')
else:
applicant = Applicant(job=job)
form = ApplicantForm(instance=applicant)
bottom_form = ApplicantFormBottom(instance=applicant)
education_formset = EducationInlineFormSet(instance=applicant)
qualification_formset = QualificationInlineFormSet(instance=applicant)
employment_formset = EmploymentInlineFormSet(instance=applicant)
c = {
'job' : job,
'form' : form ,
'bottom_form' : bottom_form,
'education_formset' : education_formset,
'qualification_formset' : qualification_formset,
'employment_formset' : employment_formset,
}
return render(request, 'jobs/application.html', c)
In order to customise the formset I defined the following:
class BaseFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
and pass use it as follows:
EducationInlineFormSet = inlineformset_factory(Applicant, Education, extra=1, can_delete=False, formset=BaseFormSet)
This returns the above error and having read around a lot I'm still none the wiser how I can keep passing an instance to the formset.
Any help would be greatly appreciated.
Regards,
Chris.
I had a similar issue - the problem was the customised formset.
Try subclassing from BaseInlineFormSet (not BaseModelFormSet).
Here is the relevant section of the docs.

Filtering data with __range

I'm using django_tables2 thus part of the code is dependent on this package, but this should be irrelevant to the overall problem.
forms.py
class PersonForm(forms.Form):
date_from = forms.DateField(input_formats='%d/%m/%Y')
date_to = forms.DateField(input_formats='%d/%m/%Y')
views.py
def filter(request):
table = PersonTable(Person.objects.all())
if request.method == 'POST':
form = PersonForm(request.POST)
if form.is_valid():
date_from = form.cleaned_data['date_from']
date_to = form.cleaned_data['date_to']
result_filtered = table.filter(date__range=(date_from, date_to))
RequestConfig(request, paginate={"per_page": 100}).configure(table)
return render(request, "people.html", {
"table": result_filtered })
args = {}
args.update(csrf(request))
args['form'] = PersonForm()
args['table'] = table
RequestConfig(request, paginate={"per_page": 100}).configure(table)
return render(request, 'people.html', args)
Simply, filtering is not working. I can see the entire table, but when I try to filter nothing happens. Can you see what's wrong?
I'm pretty sure you need to call .filter() on the query set rather than the table. For example:
result_filtered = PersonTable(Person.objects.filter(date__range=(date_from, date_to))
Also, on this line:
RequestConfig(request, paginate={"per_page": 100}).configure(table)
You are passing in table. You should pass in result_filtered instead.
This is one way I'd do it, assuming your Person model has a date field:
def filter(request):
if 'date_from' in request.GET and 'date_to' in request.GET:
# form data has been submitted
form = PersonForm(request.GET)
if form.is_valid():
date_from = form.cleaned_data['date_from']
date_to = form.cleaned_data['date_to']
people = Person.objects.filter(date__range=(date_from, date_to))
table = PersonTable(people)
else:
table = PersonTable(Person.objects.all())
else:
form = PersonForm()
table = PersonTable(Person.objects.all())
RequestConfig(request, paginate={"per_page": 100}).configure(table)
args = {}
args.update(csrf(request))
args['form'] = form
args['table'] = table
return render(request, 'people.html', args)
This binds the form if both its expected fields are present, and limits the queryset according to the results if valid. If not valid, it renders the bound form and the table built from the unlimited table. If form data was not submitted, it renders the table built from the unlimited table.
Your form tag's method attribute should be GET rather than POST, if using this design.
This doesn't quite follow the usual Django patterns for form handling because the form isn't actually making any changes, so you can use GET and don't need to return a redirect on success.

Filter only if the value is defined in Django

I have the following view:
def process(request):
if request.method == 'POST':
data = request.POST
results = Specs.objects.filter(screenGroup = data['screen_user'], storage = data['storage_user'], mSystem = data['system_user'] )
context = {'results' : results}
return render(request, 'process.html', context)
When the user inputs the three values it filters correctly, but when it just inputs one or two (or nothing), then it filters passing the value None. Is there any way to ignore the filter if it's not set?
Thanks!
EDIT:
The following code is working, but it's obviously a very unefficient way:
def process(request):
if request.method == 'POST':
data = request.POST
if(data['screen_user'] != None):
results = Specs.objects.filter(screenGroup = data['screen_user'])
elif (data['storage_user'] != None):
results = Specs.objects.filter(storage = data['storage_user'])
else:
results = Specs.objects.all()
#plus all the other options...
context = {'results' : results}
return render(request, 'process.html', context)
You can build the filter beforehand:
def process(request):
if request.method == 'POST':
data = request.POST
spec_filter = {}
for attribute in ['screenGroup', 'storage', 'mSystem']:
if attribute in data and data[attribute]:
spec_filter[attribute] = data[attribute]
results = Specs.objects.filter(**spec_filter)
context = {'results' : results}
return render(request, 'process.html', context)
NB: To use this verbatim you would have to change the names of the variables being passed in the request.POST to match those in the Specs model. I did this just to illustrate, but you can easily use the same principle with your variable names. In that case you'll have to be a bit more verbose.
It's called validating your form.. There are two ways of doing this:
create a django form and use myform.is_valid(). You can read about it in the docs
validate it yourself with a few 'if' statements (either on server side or with javascript before sending the ajax call)

django formset update existing

I want to create something similar as django admin changelist view with list_editable items...
I succeeded in creating the view. But when I post it dies on validation errors.
if request.POST:
formset_class = modelformset_factory(Job)
formset =formset_class(request.POST, request.FILES)
if formset.is_valid():
formset.save()
The problem is that I have only a couple of attributes editable. Therefore some of them are not part of POST and model complains about them being mandatory.
But I want to UPDATE objects not create them. Basically I really want the same thing admin does when having set list_editable but in my own view
I wanted a functionality just like admin using list_editable, so I went for it and pretty much copied the code from options.py of django source. I retrieved admin for my object and then saved original values (function fix_old_job_admin sets them back)
This code solved my problem
job_admin = admin.site._registry[Job]
# save old values so that you can go back to them later
old_list_display = job_admin.list_display
old_list_filter = job_admin.list_filter
old_ordering = job_admin.model._meta.ordering
job_admin.list_editable = ("time", "what", "approved")
cl = ChangeList(request, job_admin.model, job_admin.list_display, job_admin.list_display_links, job_admin.list_filter, job_admin.date_hierarchy, job_admin.search_fields, job_admin.list_select_related, job_admin.list_per_page, job_admin.list_editable,job_admin.admin_site, job_admin)
# options.py from django framework lines 1181-1208 (v. 1.4)
if request.POST:
FormSet = job_admin.get_changelist_formset(request)
formset =FormSet(request.POST, request.FILES, queryset=cl.result_list)
if formset.is_valid():
changecount = 0
for form in formset.forms:
if form.has_changed():
obj = job_admin.save_form(request, form, change=True)
job_admin.save_model(request, obj, form, change=True)
job_admin.save_related(request, form, formsets=[], change=True)
change_msg = job_admin.construct_change_message(request, form, None)
job_admin.log_change(request, obj, change_msg)
changecount += 1
if changecount:
if changecount == 1:
name = force_unicode(job_admin.model._meta.verbose_name)
else:
name = force_unicode(job_admin.model._meta.verbose_name_plural)
msg = ungettext("%(count)s %(name)s was changed successfully.",
"%(count)s %(name)s were changed successfully.",
changecount) % {'count': changecount,
'name': name,
'obj': force_unicode(obj)}
job_admin.message_user(request, msg)
# call function that sets admin with original values
fix_old_job_admin(job_admin, old_list_display, old_ordering, old_list_filter)
return HttpResponseRedirect(request.get_full_path())
FormSet = job_admin.get_changelist_formset(request)
cl.formset = FormSet(queryset=cl.result_list)
context = Context({
'app_label': ContentType.objects.get_for_model(Lawyer).app_label,
'verbose_name_plural': Job._meta.verbose_name_plural.title(),
"cl": cl,
'request': request,
})
# call function that sets admin with original values
fix_old_job_admin(job_admin, old_list_display, old_ordering, old_list_filter)
return render_to_response('yourtemplate/similar_to_changelist.html', context, RequestContext(request))

Categories

Resources