I want to extend Wagtail's PageLinkHandler to combine an internal PageChooser link with an AnchorLink, so the template output is <a href="/mypage#myanchor".
class AnchorPageLinkHandler(PageLinkHandler):
identifier = 'page_anchor'
#staticmethod
def get_model():
return Page
#classmethod
def get_instance(cls, attrs):
return super().get_instance(attrs).specific
#classmethod
def expand_db_attributes(cls, attrs):
try:
page = cls.get_instance(attrs)
hash_id = attrs["hash_id"]
return '<a href="{}#{}">'.format(escape(
page.localized.specific.url), hash_id)
except Page.DoesNotExist:
return "<a>"
#hooks.register('register_rich_text_features')
def register_link_handler(features):
features.register_link_type(AnchorPageLinkHandler)
I have got this far, but have 2 problems: i) page_anchor does not show up in the link editor widget, how do I enable this? ii) how do I add the hash_id text input to the widget when I do enable it?
Related
I have been working on a small project which is a web-crawler template. Im having an issue in pycharm where I am getting a warning Unresolved attribute reference 'domain' for class 'Scraper'
from abc import abstractmethod
import requests
import tldextract
class Scraper:
scrapers = {}
def __init_subclass__(scraper_class):
Scraper.scrapers[scraper_class.domain] = scraper_class # Unresolved attribute reference 'domain' for class 'Scraper'
#classmethod
def for_url(cls, url):
k = tldextract.extract(url)
# Returns -> <scraper.SydsvenskanScraper object at 0x000001E94F135850> & Scraped BBC News<!DOCTYPE html><html Which type annotiation?
return cls.scrapers[k.registered_domain](url)
#abstractmethod
def scrape(self):
pass
class BBCScraper(Scraper):
domain = 'bbc.co.uk'
def __init__(self, url):
self.url = url
def scrape(self):
rep = requests.Response = requests.get(self.url)
return "Scraped BBC News" + rep.text[:20] # ALL HTML CONTENT
class SydsvenskanScraper(Scraper):
domain = 'sydsvenskan.se'
def __init__(self, url):
self.url = url
def scrape(self):
rep = requests.Response = requests.get(self.url)
return "Scraped Sydsvenskan News" + rep.text[:20] # ALL HTML CONTENT
if __name__ == "__main__":
URLS = ['https://www.sydsvenskan.se/', 'https://www.bbc.co.uk/']
for urls in URLS:
get_product = Scraper.for_url(urls)
r = get_product.scrape()
print(r)
Of course I could ignore it as it is working but I do not like to ignore a warning as I believe pycharm is smart and should solve the warning rather than ignoring it and I wonder what is the reason of it warns me regarding that?
There are a few different levels on how you can remove this warning:
Assign a default value:
class Scraper:
scrapers = {}
domain = None # Or a sensible value of one exists
You can in additon or alternatly annotate the type.
from typing import ClassVar
class Scraper:
scrapers: ClassVar[dict[str, 'Scraper']] = {}
domain: ClassVar[str]
Note that ClassVar is required because otherwise it is assume that they are instance attributes.
To ignore it, put
# noinspection PyUnresolvedReferences
on the line above the line causing the warning.
Just tell yrou Scraper class that this attribut exists
class Scraper:
scrapers = {}
domain: str
def __init_subclass__(scraper_class):
Scraper.scrapers[scraper_class.domain] = scraper_class
I'm trying to initiate a property inside a class but it doesn't seem to work.
The class should use another class. this is the code I've made:
Book.py:
from Paragraph import Paragraph as Paragraph
'''definitions'''
class Book:
def __init__(self, book):
self._paragraphs = book
'''paragraphs property'''
#property
def paragraphs(self):
return self._paragraphs
#paragraphs.setter
def paragraphs(self, book):
paragraph_0 = Paragraph(book[0x0:0x100])
paragraph_1 = Paragraph(book[0x200:0x300])
paragraph_2 = Paragraph(book[0x300:0x400])
paragraph_3 = Paragraph(book[0x400:0x500])
self._paragraphs = [paragraph_0, paragraph_1, paragraph_2, paragraph_3]
Paragraph.py:
'''definitions'''
class Paragraph:
def __init__(self, paragraph):
self._paragraph = paragraph
self._first_section = paragraph[0x0:0x10]
self._second_section = paragraph[0x10:0x100]
'''paragraph property'''
#property
def paragraph(self):
return self._paragraph
#paragraph.setter
def paragraph(self, paragraph):
self._paragraph = paragraph
'''first_section property'''
#property
def first_section(self):
return self._first_section
#first_section.setter
def first_section(self, first_section):
self._first_section = first_section
'''second_section property'''
#property
def second_section(self):
return self._second_section
#second_section.setter
def second_section(self, second_section):
self._second_section = second_section
Then I create a Book instance:
first_book = Book(some_hex_list)
And I expect to have 4 paragraphs in first_book._paragraphs and each paragraph should have a first and a second section property (as in the Paragraph class). Instead first_book._paragraphs just contains the original some_hex_list data.
I'd like to create a Book instance and initiate it so in the end I should get something like this:
first_book
-->_paragraphs
----->paragraph_0
---------->_first_section
---------->_second_section
----->paragraph_1
---------->_first_section
---------->_second_section
----->paragraph_2
---------->_first_section
---------->_second_section
----->paragraph_3
---------->_first_section
---------->_second_section
Thanks!
I'm creating a page with wagtail where I need to know the previous and next sibling of the current page:
In my portrait page model, I tried to define two methods to find the correct urls, but I'm missing a crucial part. To get the first sibling, I can just do the following:
class PortraitPage(Page):
...
def first_portrait(self):
return self.get_siblings().live().first().url
There is the first() and last() method, but there doesn't seem to be a next() or previous() method to get the direct neighbours (in the order that they are arranged in the wagtail admin).
Is there any way to achieve this?
Django-Treebeard provides get_next_sibling and get_prev_sibling which will return your direct siblings in the tree, but these are not necessarily your next published sibling. To request those you can use:
prev = page.get_prev_siblings().live().first()
next = page.get_next_siblings().live().first()
Which can obviously also be chained with any other queryset operations.
After going through the debugger for a while, I found out that wagtail already has two methods: get_prev_sibling() and get_next_sibling().
So the methods could look like this (accounting for the first page in the previous method and the last item in the next method):
def prev_portrait(self):
if self.get_prev_sibling():
return self.get_prev_sibling().url
else:
return self.get_siblings().last().url
def next_portrait(self):
if self.get_next_sibling():
return self.get_next_sibling().url
else:
return self.get_siblings().first().url
Here's a version handling non-published siblings.
def next_portrait(self):
next_sibling = self.get_next_sibling()
if next_sibling and next_sibling.live:
return next_sibling.url
else:
next_published_siblings = self.get_next_siblings(
inclusive=False
).live()
if len(next_published_siblings):
return next_published_siblings[0].url
return self.get_siblings().live().first().url
def prev_portrait(self):
previous_sibling = self.get_prev_sibling()
if previous_sibling and previous_sibling.live:
return previous_sibling.url
else:
previous_published_siblings = self.get_prev_siblings(
inclusive=False
).live()
if len(previous_published_siblings):
return previous_published_siblings[0].url
return self.get_siblings().live().last().url
You can define properties in your class that inherits from Page
Siblings
If you want the siblings of an instance of Page, you can use the following (based on Danielle Madeley's answer):
class PortraitPage(Page):
# ...
#property
def next_sibling(self):
return self.get_next_siblings().live().first()
#property
def prev_sibling(self):
return self.get_prev_siblings().live().first()
Siblings of the same class
If you want the the siblings of PortraitPage, specify self.__class__ in the type method as follows:
class PortraitPage(Page):
# ...
#property
def next_sibling(self):
return self.get_next_siblings().type(self.__class__).live().first()
#property
def prev_sibling(self):
return self.get_prev_siblings().type(self.__class__).live().first()
Template
If you want to use them in a template, after defining the properties, do the following:
{# This is a template #}
Previous Sibling: {{ page.next_sibling }}
Next Sibling: {{ page.prev_sibling }}
self.get_siblings() falls over if you want to do any filtering based on properties only found in the subclass since the PageQuerySet results are of type Page.
For me, I have a blog index page that can be filtered by category or tag.
The bog detail page has cards for the next and previous blog post at the end.
I wanted those prev/next posts to be according to the filter I landed on that page from.
To get around this, you need to query the objects belonging to the subclass (eg BlogDetailPage), filter those, then get the prev/next post using class.objects.sibling_of(self):
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
siblings = self.__class__.objects.sibling_of(self).live()
category_filter = request.GET.get("category", None)
tag_filter = request.GET.get("tag", None)
if category_filter:
siblings = siblings.filter(categories__slug__in=category_filter.split(","))
context["filter"] = '?category=' + category_filter
elif tag_filter:
siblings = siblings.filter(tags__slug__in=tag_filter.split(','))
context["filter"] = '?tag=' + tag_filter
else:
context["filter"] = ''
context["next_post"] = siblings.filter(path__gt=self.path).first()
context["previous_post"] = siblings.filter(path__lt=self.path).first()
return context
I used self.__class__.objects.sibling_of(self) as this is in a super class with sub classed blog pages.
When I'm using wtforms, I want to customise a ButtonField.
I read the Docs and i wrote three classes ButtonFiled() ButtonWidget(object) and ButtonInput(Input).
I almost copy the codes from the packages, but it act not the same as SubmitField. Like the picture below--i can't post a Pic, so i give the url.
My Customise button will always be covered by a div and always a Label shows...
My Codes:
# !/usr/bin/env python
# coding: utf-8
'''
'''
from werkzeug.utils import escape
from wtforms import BooleanField,Field
from wtforms.widgets import HTMLString, html_params, Input, SubmitInput
from wtforms.compat import text_type
__author__ = 'Jux.Liu'
class ButtonWidget(object):
'''
用于显示按钮(button)的部件(widget)
'''
def __call__(self, field, **kwargs):
kwargs.setdefault('name', field.name)
kwargs.setdefault('value', field.value)
kwargs.setdefault('type', "submit")
return HTMLString('<button %s>%s</button>' % (
html_params(**kwargs),
escape(field._value())
))
class ButtonInput(Input):
"""
Renders a submit button.
The field's label is used as the text of the submit button instead of the
data on the field.
"""
input_type = 'submit'
def __call__(self, field, **kwargs):
kwargs.setdefault('value', field.label.text)
return super(ButtonInput, self).__call__(field, **kwargs)
class ButtonOneField(BooleanField):
'''
定义可以将按钮(button)用于 Flask 表单(form)的域(field)
'''
widget = SubmitInput()
class ButtonTwoField(Field):
'''
定义可以将按钮(button)用于 Flask 表单(form)的域(field)
'''
widget = ButtonWidget()
def __init__(self, text, name, value, **kwargs):
super(ButtonTwoField, self).__init__(**kwargs)
self.text = text
self.value = value
self.name = name
def _value(self):
return str(self.text)
Package Codes Segment:
class SubmitField(BooleanField):
"""
Represents an ``<input type="submit">``. This allows checking if a given
submit button has been pressed.
"""
widget = widgets.SubmitInput()
class BooleanField(Field):
"""
Represents an ``<input type="checkbox">``.
:param false_values:
If provided, a sequence of strings each of which is an exact match
string of what is considered a "false" value. Defaults to the tuple
``('false', '')``
"""
widget = widgets.CheckboxInput()
false_values = ('false', '')
def __init__(self, label=None, validators=None, false_values=None, **kwargs):
super(BooleanField, self).__init__(label, validators, **kwargs)
if false_values is not None:
self.false_values = false_values
def _value(self):
if self.raw_data:
return text_type(self.raw_data[0])
else:
return 'y'
class SubmitInput(Input):
"""
Renders a submit button.
The field's label is used as the text of the submit button instead of the
data on the field.
"""
input_type = 'submit'
def __call__(self, field, **kwargs):
kwargs.setdefault('value', field.label.text)
return super(SubmitInput, self).__call__(field, **kwargs)
I am creating a Flask Website and i want to display different logout links based your current page i.e
If we’re on the home page and logged in, have this link be wrapped in h2 tags
If we’re on a different page and logged in, have this link be wrapped in underline tags
If we’re logged in, have this link wrapped in strong tags
So far i have tried upto here.
class HtmlLinks():
html =""
def set_html(self, html):
self.html = html
def get_html(self):
return self.html
def render(self):
print(self.html)
class LogoutLink(HtmlLinks):
def __init__(self):
self.html = "Logout"
class LogoutLinkH2Decorator(HtmlLinks):
def __init__(self, logout_link):
self.logout_link = logout_link
self.set_html("<h2> {0} </h2>").format(self.logout_link.get_html())
def call(self, name, args):
self.logout_link.name(args[0])
class LogoutLinkUnderlineDecorator(HtmlLinks):
def __init__(self, logout_link):
self.logout_link = logout_link
self.set_html("<u> {0} </u>").format(self.logout_link.get_html())
def call(self, name, args):
self.logout_link.name(args[0])
class LogoutLinkStrongDecorator(HtmlLinks):
def __init__(self, logout_link):
self.logout_link = logout_link
self.set_html("<strong> {0} </strong>").format(self.logout_link.get_html())
def call(self, name, args):
self.logout_link.name(args[0])
logout_link = LogoutLink()
is_logged_in = 0
in_home_page = 0
if is_logged_in:
logout_link = LogoutLinkStrongDecorator(logout_link)
if in_home_page:
logout_link = LogoutLinkH2Decorator(logout_link)
else:
logout_link = LogoutLinkUnderlineDecorator(logout_link)
logout_link.render()
I am getting Attribute error
AttributeError: 'NoneType' object has no attribute 'format'
What wrong i am doing and how to rectify it. Please Help.
So you have a few lines that looks like this:
self.set_html("<h2> {0} </h2>").format(self.logout_link.get_html())
You probably want them to look like:
self.set_html("<h2> {0} </h2>".format(self.logout_link.get_html()))
set_html returns nothing, but you try to call for format method on its returned value.
self.set_html("<strong> {0} </strong>").format(self.logout_link.get_html())