How to add custom css class to wagtail dashboard buttons - django

How can we add custom classes to wagtail dashboard buttons like 'View Live', 'Edit' Buttons for contents created. When I browse through the core files I noticed core wagtail hooks for admin page like below (I know we are not supposed to edit the core files)
if page.live and page.url:
yield PageListingButton(
_('View live'),
page.url,
attrs={'target': "_blank", 'rel': 'noopener noreferrer', 'title': _("View live version of '{title}'").format(title=page.get_admin_display_title())},
priority=30
)
If I add 'class':'custom-class' to attrs value then the default class disappears and custom-class appears
What is the right way to do this
Edit (On further investigation)
Using wagtail hooks
I created a new wagtail app to register the hook so that I was able to register the button without altering the core files, but now I have two buttons(Duplicate), but I was expecting to edit the existing button's class attrs values
from wagtail.core import hooks
from wagtail.admin import widgets as wagtailadmin_widgets
from wagtail.admin.widgets import Button, ButtonWithDropdownFromHook, PageListingButton
#hooks.register('register_page_listing_buttons')
def page_listing_buttons(page, page_perms, is_parent=False):
if page.live and page.url:
yield PageListingButton(
('View live'),
page.url,
attrs={'target': "_blank", 'rel': 'noopener noreferrer', 'title': ("View live version of '{title}'").format(title=page.get_admin_display_title())},
priority=30
)

This portion of the documentation should address your need.

Related

How to click on a element through Selenium Python

I'm trying to fetch data for facebook account using selenium browser python but can't able to find the which element I can look out for clicking on an export button.
See attached screenshot
I tried but it seems giving me an error for the class.
def login_facebook(self, username, password):
chrome_options = webdriver.ChromeOptions()
preference = {"download.default_directory": self.section_value[24]}
chrome_options.add_experimental_option("prefs", preference)
self.driver = webdriver.Chrome(self.section_value[20], chrome_options=chrome_options)
self.driver.get(self.section_value[25])
username_field = self.driver.find_element_by_id("email")
password_field = self.driver.find_element_by_id("pass")
username_field.send_keys(username)
self.driver.implicitly_wait(10)
password_field.send_keys(password)
self.driver.implicitly_wait(10)
self.driver.find_element_by_id("loginbutton").click()
self.driver.implicitly_wait(10)
self.driver.get("https://business.facebook.com/select/?next=https%3A%2F%2Fbusiness.facebook.com%2F")
self.driver.get("https://business.facebook.com/home/accounts?business_id=698597566882728")
self.driver.get("https://business.facebook.com/adsmanager/reporting/view?act="
"717590098609803&business_id=698597566882728&selected_report_id=23843123660810666")
# self.driver.get("https://business.facebook.com/adsmanager/manage/campaigns?act=717590098609803&business_id"
# "=698597566882728&tool=MANAGE_ADS&date={}-{}_{}%2Clast_month".format(self.last_month,
# self.first_day_month,
# self.last_day_month))
self.driver.find_element_by_id("export_button").click()
self.driver.implicitly_wait(10)
self.driver.find_element_by_class_name("_43rl").click()
self.driver.implicitly_wait(10)
Can you please let me know how can i click on Export button?
Well, I'm able to resolve it by using xpath.
Here is the solution
self.driver.find_element_by_xpath("//*[contains(#class, '_271k _271m _1qjd layerConfirm')]").click()
The element with text as Export is a dynamically generated element so to locate the element you have to induce WebDriverWait for the element to be clickable and you can use either of the locator strategies:
Using CSS_SELECTOR:
WebDriverWait(self.driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.layerConfirm>div[data-hover='tooltip'][data-tooltip-display='overflow']"))).click()
Using XPATH:
WebDriverWait(self.driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[contains(#class, 'layerConfirm')]/div[#data-hover='tooltip' and text()='Export']"))).click()
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
to run automation scripts on applications like facebook, youtube quite a hard because they are huge coporations and their web applications are developed by the worlds best developers but its not impossible to run automation scripts sometimes elements are generated dynamically sometimes hidden or inactive you cant just go and click
one solution is you can do by click action by xpath realtive or absolute their is not id specified as "export_button" in resource file i think this might help you
you can also find element by class name or css selector as i see in screen shot the class name is present "_271K _271m _1qjd layerConfirm " you can perform click action on that

In Django, How to get the currently running app from within a model on another app?

Basically i am trying to use .get_absolute_url() to return dynamic links in relative to the current app running, in other words reverse the model url to a different url based on which app being called.
Let me try to explain what i am trying to do by example, We have three apps
Blog (serves as a shared data layer, contains models for post, authors ... etc)
BloggerWay (serves as a view layer number one, uses the Blog app models to display content in some given layout)
TumblrWay (serves as another view layer, again uses the Blog app models to display content in some given layout)
My urls.py files goes like
----------
*Project.urls.py*
----------
urlpatterns= [
url('/blogger/', include(BloggerWay.urls.py, namespace='blogger'),
url('/tumblr/', include(TumblrWay.urls.py, namespace='tumblr'),]
----------
*BloggerWay.urls.py*
----------
urlpatterns= [
url('/post/(?P<id>\d+)', Blog.as_view(), name='blog'),]
----------
*TumblrWay.urls.py*
----------
urlpatterns= [
url('/post/(?P<id>\d+)', Blog.as_view(), name='blog'),]
My question is How can i define .get_absolute_url() method for the Post model so it knows which app we are in and return the correct url to it.
example:
if in BloggerWay return '/blogger/post'
if in TumblrWay return '/tumblr/post'
I know that i can use the reverse() function to get the url for a given named pattern and that it accepts a current_app= argument but my problem is how can i get the running app so i can pass it.
class Post(...):
def get_absolute_url(self):
WhoAmI = ... #get current app here, BUT HOW!
return reverse('post', current_app=WhoAmI)
Solutions that i want to avoid:
I can inherit the Post class in both of the apps, override the .get_absolute_url() there, hardcoding the name space of each app in it. Then use the class in my app instead of directly using the one defined as model/table.(while offcourse avoid performing migrations for that class, even better define it somewhere else than models.py)
Implement another property for get_url() for your class.
The reverse function should includes "namespace:name"
e.g
class Post(...):...
def get_blogger_url(self):
return reverse("blogger:post", kwargs={"id":self.id}) # for Blogger
def get_tumblr_url(self):
return reverse("tumblr:post", kwargs={"id":self.id}) # for Tumblr

Django Forbid HttpResponse

I am working on a tiny movie manager by using the out-of-the-box admin module in Django.
I add a "Play" link on the movie admin page to play the movie, by passing the id of this movie. So the backend is something like this:
import subprocess
def play(request, movie_id):
try:
m = Movie.objects.get(pk=movie_id)
subprocess.Popen([PLAYER_PATH, m.path + '/' + m.name])
return HttpResponseRedirect("/admin/core/movie")
except Movie.DoesNotExist:
return HttpResponse(u"The movie is not exist!")
As the code above reveals, every time I click the "play" link, the page will be refreshed to /admin/core/movie, which is the movie admin page, I just do not want the backend to do this kind of things, because I may use the "Search" functions provided by the admin module, so the URL before clicking on "Play" may be something like: "/admin/core/movie/?q=gun", if that response takes effect, then the query criteria will be removed.
So, my thought is whether I can forbid the HttpResponse, in order to let me stay on the current page.
Any suggestions on this issue ?
Thanks in advance.
I used the custom action in admin to implement this function.
So finally I felt that actions are something like procedures, which have no return values, and requests are something like methods(views) with return values...
Thanks !

Problem getting preview from Django-MarkItUp in Admin interface

I am working on a custom markup formatter for Django and I wanted to interface it with MarkItUp.
It is successfully being called when I save the field, which is of type MarkupField, but when I try to preview this field from the Admin interface using the default settings, all I get back in the preview box is plaintext.
I am using the MarkItUp version from here: http://bitbucket.org/carljm/django-markitup/src
Here are my settings:
MARKITUP_FILTER = ('util.wookie.formatter.wookie', {})
JQUERY_URL = 'js/lib/jquery.js'
In urls, I have the following line:
(r'^markitup/', include('markitup.urls')),
Any ideas?
Is something serving the assets from both the MARKITUP_MEDIA_URL the JQUERY_URL locations?

Decoupling django apps 2 - how to get object information from a slug in the URL

I am trying to de-couple two apps:
Locations - app containing details about some location (town, country, place etc)
Directory - app containing details of places of interest (shop, railway station, pub, etc) - all categorised.
Both locations.Location and directory.Item contain lat/lng coords and I can find items within a certain distance of a specific lat/lng coord.
I'd like to use the following URL structure:
/locations/<location_slug>/directory/<category_slug>/
But I don't want to make my directory app reliant on my location app.
How can I translate this url to use a view like this in my directory app?
items_near(lat, lng, distance, category):
A work around would be to create a new view somewhere that translates this - but where should I put that? if it goes in the Directory app, then I've coupled that with my Location app, and vice versa.
Would a good idea be to place this workaround code inside my project URLs file? Thus keeping clear of both apps? Any issues with doing it like this?
For your urlpattern to work, the view function invoked has to be aware of both Locations and Directories. The short answer is you can put this view function anywhere you want - it's just a python function. But there might be a few logical places for it, outside of your Directory or Location app, that make sense.
First off, I would not put that view code in in your top-level urls.py, as that file is intended for URLconf related code.
A few options of where to put your view:
Create a new view function in a file that lives outside of any particular app. <project_root>/views.py is one possibility. There is nothing wrong with this view calling the item_near(..) view from the Directory app.
# in myproject/urls.py
urlpatterns = (
...
(r'/locations/(?P<location_slug>[\w\-]+)/directory/(?P<category_slug>[\w\-]+)/',
'myproject.views.items_near_from_slug')
)
# in myproject/views.py
from directory.views import items_near
def items_near_from_slug(request, location_slug, category_slug):
location = get_object_or_404(Location, slug=location_slug)
distance = 2 # not sure where this comes from
# And then just invoke the view from your Directory app
return items_near(request, location.lat, location.lng, distance, category_slug)
Create a new app and put the code there, in <my_new_app>/views.py. There is no requirement that a Django app need to have a models.py, urls.py, etc. Just make sure to include the __init__.py if you want Django to load the app properly (if, for instance, you want Django to automatically find templatetags or app specific templates).
Personally, I would go with option 1 only if the project is relatively simple, and <project_root>/views.py is not in danger of becoming cluttered with views for everything. I would go with option 2 otherwise, especially if you anticipate having other code that needs to be aware of both Locations and Directories. With option 2, you can collect the relevant urlpatterns in their own app-specific urls.py as well.
From the django docs here if you're using django >=1.1 then you can pass any captured info into the included application. So splitting across a few files:
# in locations.urls.py
urlpatterns = ('',
(r'location/(?P<location_slug>.*?)/', include('directory.urls')),
#other stuff
)
# in directory.urls.py
urlpatterns = ('',
(r'directory/(?P<directory_slug>.*?)/', 'directory.views.someview'),
#other stuff
)
# in directory.views.py
def someview(request, location_slug = None, directory_slug = None):
#do stuff
Hope that helps. If you're in django < 1.1 I have no idea.
Irrespective of how much ever "re-usable" you make your app, inevitably there is a need for site-specific code.
I think it is logical to create a "site-specific" application that uses the views of the reusable and decoupled apps.