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.
Related
in my wagtail app, I have a model that I want to only allow certain types of users to view that model. In django I would just inherit UserPassesTestMixin. In wagtail, I will allow it based on a session data. If request.session.dados_usuarios.bu == 'Corporate KO', he will be able to view the page. I'm new to wagtail, is it possible to do this?
In django I would do it like this
class SomeView(UserPassesTestMixin, TemplateView):
...
def test_func(self):
return request.session.dados_usuario.bu == 'Corporate KO'
My model in wagtail app
class IframePage(Page):
iframe_url = models.URLField()
fabricantes_com_acesso = ParentalManyToManyField(
Fabricante,
blank=True,
verbose_name="Fabricas com Acesso"
)
content_panels = Page.content_panels + [
MultiFieldPanel([
FieldPanel('iframe_url'),
FieldPanel('fabricantes_com_acesso'),
],
heading="Informações Principais"),
]
Wagtail has page privacy settings but they are set on sections of the page tree rather than by page type. The easiest option would be if all your IframePages were in the same section of the page tree. Then you can set a page privacy setting on the parent page and all of the subpages will inherit it.
If you really need this to work per page type anywhere in the page tree, you could add a hook to set the page privacy setting on all IframePages when they are created.
So i'm trying to build something, so that users would be able to report something on site. Here's the model,
class Report(models.Model):
reporting_url = models.URLField()
message = models.TextField()
I created Form for this Model including 'message' field only because 'reporting_url' is something it needs to populate by itself depending upon the specific page from where user has clicked "Report" button.
def report(request):
url_report = ???
if request.method == 'POST':
form = ReportForm(request.POST or None)
if form.is_valid():
new_form = form.save(commit=False)
new_form.reporting_url = url_report
new_form.save()
I was wondering How can I pass the specific url to 'reporting_url' field in form depending on the Page from where user has clicked "Report" button? (Much like s we see on social Networks).
Am I doing this correctly, Or is there a better way for doing this?
Please help me with this code. Thanks in Advance!
If there is a report button on that specific page then I believe you could write custom context processor.
More info: Django: get URL of current page, including parameters, in a template
https://docs.djangoproject.com/en/1.11/ref/templates/api/
Or maybe just write it directly in the views.py in your function and set
url_report = request.get_full_path()
I think you can use the form on the same page of the URL and use:
url_report = request.get_full_path()
in the view, to get the current URL.
Else if you want to create a separate view for the reporting form. You can use
url_report = request.META.get('HTTP_REFERER')
to get the previous or refering URL which led the user to that page.
request.META.get('HTTP_REFERER') will return None if it come from a different website.
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.
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 !
I am new to Wagtail and python, so could apprectiate some help with my problem.
I have a web app (wagtail web site + rest api backend).
On my website I have 2 pages:
HomePage with list of accessible objects (e.g. photos)
PhotoPage with a detailed information on photo
What I want to achive:
When I click on photo on homepage I am redirected to the photopage
I fill the photopage with information I got from backend
And the photopage url is smth like this http://example.com/photo?id=12345
So, I want to
have 1 model for photopage
fill photopage based on a requested url (i.e. from homepage I redirect user to example.com/photo?id=12345 and it is filled with information on photo with id=12345)
I guess there should be some middleware to parse requested url to get the id and fill the page with info from API. Is there any standard solution to this issue?
Page objects (and any classes that inherit from Page) have a get_context method that can be used to add context pre-rendering of your templates.
from django.shortcuts import get_object_or_404
class PhotoPage(Page):
# your model definition ...
def get_context(self, request):
context = super(PhotoPage, self).get_context(request)
photo_pk = request.GET.get('id',None)
photo = get_object_or_404(YourPhotoModel,pk=photo_pk) # if no matching photo, return 404. You can do whatever you like instead :)
context['photo'] = photo
return context
Now in your photo template you can access your Photo model instance directly...
{{ photo.some_attribute }}
{{ photo.some_other_attribute }}