I need to enable some pages to write an arbitrary URL that does not depend on the structure of the site.
For example I have structure:
/
/blog
/blog/blogpost1
/blog/blogpost2
But, for example, I need change url from /blog/blbogpost2 to /some/blogpost/url1
For this, I decided to give the opportunity to handle any URL of the main page of the site.
class IndexPage(RoutablePageMixin, Page):
...
#route(r'^(?P<path>.*)/$')
def render_page_with_special_path(self, request, path, *args, **kwargs):
pages = Page.objects.not_exact_type(IndexPage).specific()
for page in pages:
if hasattr(page, 'full_path'):
if page.full_path == path:
return page.serve(request)
# some logic
But now, if this path is not found, but I need to return this request to the standard handler. How can I do it?
This isn't possible with RoutablePageMixin; Wagtail treats URL routing and page serving as two distinct steps, and once it's identified the function responsible for serving the page (which, for RoutablePageMixin, is done by checking the URL route given in #route), there's no way to go back to the URL routing step.
However, it can be done by overriding the page's route() method, which is the low-level mechanism used by RoutablePageMixin. Your version would look something like this:
from wagtail.core.url_routing import RouteResult
class IndexPage(Page):
def route(self, request, path_components):
# reconstruct the original URL path from the list of path components
path = '/'
if path_components:
path += '/'.join(path_components) + '/'
pages = Page.objects.not_exact_type(IndexPage).specific()
for page in pages:
if hasattr(page, 'full_path'):
if page.full_path == path:
return RouteResult(page)
# no match found, so revert to the default routing mechanism
return super().route(request, path_components)
Related
I am using a django template to generate pdf via feeding it a context object from the function but not the view, it works fine in case of view, but I am not able to load the local static images on the template from the function. but this is possible in view because there I can tell which base path to use. But I not able to do the same in the function.
As you can see I can how I am getting the base url from the view. Here I can get because I have requests object but in function I do not have any requests object. So images are not loading.
html = HTML(string=html_string, base_url=request.build_absolute_uri('/'))
This is how I am trying to do in the function:
html_string = render_to_string('experiences/voucher.html', data)
html = HTML(string=html_string, base_url=settings.STATIC_ROOT)
result = html.write_pdf("file_new.pdf", stylesheets=[css],optimize_images=True)
I would like to know how can I tell, where are my images so that images can be rendered on the pdf.
It was not working because base_url had not way to know where the images are located especially on the running server, so I had to explicitly define the path to the local resources so I did something like this:
first I added an envoirnment variable in my .env file:
like HOST=http://localhost:8000 and then I get this url in my actuall code like this:
path = os.environ["HOST"]+"/static/"
and at the end i pass this path to base_url parameter in HTML()
html = HTML(string=html_string, base_url=path)
and after all this it worked like a charm.
Is there a way to write a step that works for multiple keywords. Like say my feature is:
Scenario: Something happens after navigating
Given I navigate to "/"
And say some cookie gets set
When I navigate to "/some-other-page"
Then something happens because of that cookie
I'm trying to avoid having to define both:
#given('I navigate to "{uri}"')
def get(context, uri):
current_url = BASE_URL + uri
context.driver.get(current_url)
#when('I navigate to "{uri}"')
def get(context, uri):
current_url = BASE_URL + uri
context.driver.get(current_url)
If you only define one and try to use it as both you get a raise NotImplementedError(u'STEP: error. With the above example it's not that bad because the step is simple but it seems like it's bad practice to repeat code and you could have the same thing happening with something more complicated, to me it seems like it would make sense if there was like a #all or #any keyword.
Apologies if this has been answered somewhere but it's a hard thing to search for as it's hard to find unique search terms for this type of question
It turns out this can be done using #step. e.g.
from behave import step
#step('I navigate to "{uri}"')
def step_impl(context, uri):
current_url = BASE_URL + uri
context.driver.get(current_url)
Will work for:
Scenario: Demo how #step can be used for multiple keywords
Given I navigate to "/"
When I navigate to "/"
Then I navigate to "/"
Note: Figured this out from the ticket which led to this file.
If you do not want to use #step, you can also do:
#and(u'I navigate to "{uri}"')
#when(u'I navigate to "{uri}"')
#given(u'I navigate to "{uri}"')
def get(context, uri):
current_url = BASE_URL + uri
context.driver.get(current_url)
There are conceptual differences between what the #given, #when and #then decorators stand for. You have situations where a step applies to all, some, or only one.
It is all to easy to use #step when the step only applies to 2 situations, and then rely on the test writers to only use the step in the right circumstances. I would encourage people not to do that. Use the following example instead.
#given('step text')
#when('step text')
def step_impl(context):
pass
However when a step is truly applicable to all cases, a good example is a delay step, then use the #step decorator:
#step('delay {duration} second(s)')
def step_impl(context, duration):
time.sleep(float(duration))
You can try something like this:
As a web user
Given I navigate to "/"and say some cookie gets set
Then I navigate to "/some-other-page"
And something happens because of that cookie
Its working for me. When you write "And" statement following "Then" statement, it considers it as two "Then" statements. Also you should include u' inside given and then statements parenthesis.
Try as below:
#given(u'I navigate to "{uri}"')
def get(context, uri):
current_url = BASE_URL + uri
context.driver.get(current_url)
#given(u'say some cookie gets set')
def get(context, uri):
current_url = BASE_URL + uri
context.driver.get(current_url)
#then(u'I navigate to "/some-other-page"')
def step_impl(context):
//your code
#then(u'something happens because of that cookie')
def step_impl(context):
//your code
I have a bottle site that loads content via getJSON() requests.
To handle normal requests made when navigating the site, getJSON() requests are made to a Python script which dumps the results in JSON format.
Push/pop state is used to change the URL when the dynamic content is loaded.
To handle this same dynamic content when directly accessing the URL, eg reloading the page, I create a conditional which loads the bottle template and passes the path to the getJSON() request, which then loads the dynamic content.
#route('/')
#route('/<identifier>')
def my_function(identifier='index'):
# do things with certain paths using if and elif conditionals
#
# handle the getJSON() path
elif value_passed_to_getJSON.startswith("part_one/"):
# get the path after / , in this example it should be 'part_two'
my_variable = value_passed_to_getJSON.split("/")[1]
# perform database query with my_variable
response.content_type = 'application/json'
return dumps(cursor)
# and later for direct URL access, eg reloading the page, this essentially routes the query
# back to the getJSON() path handler above.
elif identifier == "part_one/part_two":
return template('site_template',value_passed_to_getJSON="/" + identifier)
This setup is working when the identifier is something like part_one but not in the format above ie part_one/part_two, in that case a 404 is raised.
As another test, if I simply put:
elif identifier == "part_one/part_two":
return "hello"
I also get a 404 with a Firebug error on GET part_two.
I am wondering if this is because the initial route #route('/<identifier>') only contains a single value and forward slash?
Does it need an extra wildcard to handle the two parts of the path?
Demonstrated Solution (per comment below)
#route('/')
#route('/<identifier:path>')
#view('my_template.tpl')
def index(identifier='index'):
if identifier == 'part_one/part_two':
return "hello"
else:
return "something standard"
I'm using scrapy to crawl a multilingual site. For each object, versions in three different languages exist. I'm using the search as a starting point. Unfortunately the search contains URLs in various languages, which causes problems when parsing.
Therefore I'd like to preprocess the URLs before they get sent out. If they contain a specific string, I want to replace that part of the URL.
My spider extends the CrawlSpider. I looked at the docs and found the make_request_from _url(url) method, which led to this attempt:
def make_requests_from_url(self, url):
"""
Override the original function go make sure only german URLs are
being used. If french or italian URLs are detected, they're
rewritten.
"""
if '/f/suche' in url:
self.log('French URL was rewritten: %s' % url)
url = url.replace('/f/suche/pages/', '/d/suche/seiten/')
elif '/i/suche' in url:
self.log('Italian URL was rewritten: %s' % url)
url = url.replace('/i/suche/pagine/', '/d/suche/seiten/')
return super(MyMultilingualSpider, self).make_requests_from_url(url)
But that does not work for some reason. What would be the best way to rewrite URLs before requesting them? Maybe via a rule callback?
Probably worth nothing an example since it took me about 30 minutes to figure it out:
rules = [
Rule(SgmlLinkExtractor(allow = (all_subdomains,)), callback='parse_item', process_links='process_links')
]
def process_links(self,links):
for link in links:
link.url = "something_to_prepend%ssomething_to_append" % link.url
return links
As you already extend CrawlSpider you can use process_links() to process the URL extracted by your link extractors (or process_requests() if you prefer working at the Request level), detailed here
I have a city card that I display with this link:
/<country_name>/<city_name>
I can access to this card from two different links:
/<country_name>/
/<country_name>/pick-cities
When the card is opened I want to return back to the URL visited before (one of the two below).
I have used a target which I affect a referring:
target = request.META['HTTP_REFERER']
But the problem is when I make some actions on the card then request.META['HTTP_REFERER'] become the card's URL! (like history.back() in JavaScript)
Is there an other way to link back to the visited URL before?
You could save the request.META['HTTP_REFERER'] in sessions and use it when needed.
Store it only when you come to card url which is different from current url, so you will not save it when you edit it.
Something like
def city_card(request):
# do your stuff
if not request.session.get('REFERRER') and request.session['REFERRER'] != request.path
request.session['REFERRER'] = request.path
# use request.session['REFERRER'] when you want to redirect there
NOTE: You may have to use something else than request.path to actual url verification.