forms.py
class search_form(forms.Form):
options = categories.objects.all()
category = forms.ModelChoiceField(options, initial={'All':'All'}, label='')
search = forms.CharField(max_length=100, label='', required=False)
This form is used for searching for items. And right now I have it implemented on the index page and it works as expected. The index (home) page has its own view that makes use of this form, but I have a base template (base.html) that every page on the site extends. The base template holds the menu bar and the footer of the site. I need to add the form to the base class and have it function in every template that extends it.
Is there a way to do this?
You can add a custom context processor, which is useful for passing data to every template context, which will give every template access to your form.
As explained in the docs, you need to make a function that will return a dictionary containing your form, and point to it in the settings.
Related
I am using Django Formtools to create a multistep form for a Job posting process. In one of the forms, I have Job Questions which I want the user to add dynamically, say a checkbox that generates the question form if they are interested in adding questions. They should have a button to create as many questions as possible. Now my challenge is that when I use normal model forms, I am able to complete the job posting process but if i replace the question form with a model formset and include it in the form_list I get key errors.
Secondly, if I try the various Javascript responses on adding fields dynamically such as this stack overflow response, I get form validation errors. Just to mention, the question Form uses the same model as the other forms (Job Model) thus my expectation is that regardless of how many questions are added they will be save to the Job Model. Does anyone know how to go about this? Adding fields in Django formtools dynamically and saving to the model? My Form tools wizard looks as below:
class JobWizard(SessionWizardView):
form_list=[JobForm7,JobForm1,JobForm2,JobForm3, JobForm4,JobForm5,JobForm6 ]
file_storage= FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'jobs'))
template_name="jobs/jobforms.html"
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def done(self, form_list, form_dict, **kwargs):
form_dict = self.get_all_cleaned_data()
categories = form_dict.pop('categories')
sub_categories = form_dict.pop('sub_categories')
job_question = form_dict.pop('job_question')
print(job_question)
print("_________________________")
job=Job.objects.create(**form_dict)
job.categories=categories
job.job_question=job_question
for sub_category in sub_categories:
job.sub_categories.add(sub_category)
# for question in job_question:
# job.job_question.add(question)
job.save()
return redirect('job_list')
And my model looks as below:
class Job(models.Model):
...#Other fields
# Form 4
job_question=models.CharField(max_length=20, default="")
# Form 5
job_freelancers_number=models.IntegerField(default=1)
So I was able to handle this by using Django Dynamic Formset library.All I needed was create the jquery.formset.js in my STATIC_URL then reference the same in my template after jquery. Then in my template < /script> section i passed below:
<script type="text/javascript">
$(function() {
$('#job-question').formset();
})
The Wagtail Form Builder documentation states:
form_page.html differs from a standard Wagtail template in that it is
passed a variable form, containing a Django Form object, in addition
to the usual page variable.
But in my current project, I need to embed a contact form (implemented as a Form Builder page) in another page. In the model for that target page, I'm using a PageChooserPanel to let an editor select the form page to embed. In other words:
class TargetPage(Page):
[...snip...]
contact_form = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
content_panels = Page.content_panels + [
[...snip...]
PageChooserPanel('contact_form', 'FormPage'),
]
My problem is in the template for the target page. I can access the attributes of the form page via page.contact_form, but since this page doesn't have a form object passed in, I can't figure out how to render my fields.
I am guessing that I need to override my target page's get_context() so that it includes the form object I need. But I can't figure out how to get that object. Can some kind soul put me on the right track?
After a night's sleep, the answer turned out to be relatively obvious. The missing link is the get_form() method of a Wagtail FormPage. I'm now using this in my TargetPage model:
def attached_form(self):
return self.contact_form.specific.get_form()
And thus, in my template, I can refer to attached_form to get my fields.
I have 2 templates to render one listview and I am choosing the template according to the request url given by the user. I know that, I can add 2 classes for 2 templates on 2 seperate urls respectively. For example
class MyListView1(generic.ListView):
template_name = 'myapp/list_one.html'
.....
.....
class MyListView2(generic.ListView):
template_name = 'myapp/list_two.html'
.....
.....
But is there a way if I could check the url request inside one class and render the template according to it inside one listview class ? something like
class MyListView(generic.ListView):
if request.path == '/list1'
template_name = 'myapp/list_one.html'
if request.path == '/list2'
template_name = 'myapp/list_two.html'
I know this is not a valid code but just to visualise
Whenever you want to do something dynamic in a generic view, it needs to be in a method. This page shows the methods available for ListViews, and you can see that it includes get_template_names() which should do exactly what you want.
An alternative though would be to have two separate view classes, each defining their own template name, that inherit from a common base class which defines the rest of the shared functionality.
Just pass template from urls.py like
path("/list1",views.MyListView.as_view(template_name="myapp/list_one.html"),name="list1")
path("/list2",views.MyListView.as_view(template_name="myapp/list_two.html"),name="list2")
Let's say I have an Contact object and I want to have two groups of contact Formsets in django(1.8) divided by fieldset tag in html template. I use modelformset_factory. Regardless I use one or two different factory functions, fields in these two formsets have same id in html. Since http.Request.body is dictionary, I lose information about one of the two formsets.
contacts_formset = modelformset_factory(
models.Contact,
form=forms.ContactDetailForm,
extra=2)
contacts_escalation_formset_new = contacts_formset(
queryset=models.Contact.objects.none())
contacts_other_formset_new = contacts_formset(
queryset=models.Contact.objects.none())
in HTML:
input id="id_form-0-name" maxlength="155" name="form-0-name" type="text"
input id="id_form-0-name" maxlength="155" name="form-0-name" type="text"
For simple django form, there is keyword "prefix=..." . But this factory function does not have this argument. How can I solve it?
The modelformset_factory class returns a FormSet class. This FormSet class has a optional prefix argument, similar to Form classes.
contacts_escalation_formset_new = contacts_formset(
prefix='escalation',
queryset=models.Contact.objects.none(),
)
contacts_other_formset_new = contacts_formset(
prefix='other'
queryset=models.Contact.objects.none(),
)
See the docs on using more than one formset in a view for another example.
Im trying to use Django Suit's form includes to add a button to the list display of all my subscribers in the admin. In the documentation it says to add this to your admin.py file in the right app.
class SubscriberAdmin(admin.ModelAdmin):
list_display = ('email', 'date')
readonly_fields = ('email', 'date')
def has_add_permission(self, request):
return False
suit_form_includes = (
('admin/suit_includes/suit_csv.html', 'top'),
)
However this only appears when clicking into an instance of an object, and doesn't show up on the admin page that shows the entire list of objects in the database. Is there a way to do this with Django Suit ? I had trouble finding anything on google.
suit form include template:
<button class="btn btn-info">Export to File</button>
Admin instance display (Where its appearing):
Admin list display (Where I want it to appear):
What's doing django-suit, here, is that it is including your HTML snippet in the change_form that is displayed for your model, the change_form being where you can modify your model and save the changes into the database.
Where you want it to appear is the "change_list", aka the place where you can see all of your instances of that model in your database.
To add it your html snippet, you should extend your change_list.html with your own snippet : More info on expanding templates in the official documentation
Good luck !