Wagtail CMS: Embeds cannot be found for all sources except YouTube - python

I have started using Wagtail as an alternative to PHP solutions. I installed Wagtail following the docs and a small tutorial to get started. I have no custom settings in my settings/base.py concerning the WAGTAILEMBEDS_FINDERS.
The only changes I made so far to the Home Page:
from django.db import models
from wagtail.core.models import Page
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel
class HomePage(Page):
templates = "home/home_page.html"
banner_title = models.CharField(max_length=100, blank=False, null=True)
banner_imgname = models.CharField(max_length=100, blank=False, null=True)
body = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel("banner_title"),
FieldPanel("banner_imgname"),
FieldPanel('body', classname="full"),
]
And this is the simple home_page template:
{% extends "base.html" %}
{% load static %}
{% load wagtailcore_tags %}
{% block body_class %}template-homepage{% endblock %}
{% block content %}
{{ self.banner_title }}
{{ self.imgname_title }}
{{ page.body|richtext }}
{% endblock %}
All simple outputs of text from a CharField and RichTextField work fine, but the embed feature, which I -unfortunately - need the most (blog sharing all kinds of embed stuff), does not work properly.
I tried Soundcloud, Deviantart, Vimeo, Instagram. Only YouTube embeds. (To confirm there are no other restrictions for the chosen links I embedded them in an editor of a WP installation (sorry :-)).
There is also this issue on github, but it is not just an Instagram issue but a general embed problem I think. I followed the given links provided there but did not find a solution, everything "seems" right.
Question is: Is it an issue? Do I do sth. wrong?
Are there reliable, stable workarounds using other editors you can recommend? I'd really love to stick to Wagtail and am willing to put more effort in learning, but need this feature quite desperately.
My Setup:
Django 2.2.3
Wagtail v2.6
OSX 10.12.6
Python 3.7.3
Browser: Firefox & Chrome tested (latest)
EDIT:
I thought this is a RichTextField issue only, but I tried another way of embedding with {% embed %} tags like suggested in the docs which also does not work for me: In models.py I added:
embedcontent_url = models.URLField("Embed Content URL", blank=True)
And in the home_page.html:
{% load wagtailembeds_tags %}
{% embed page.embedcontent_url %}
And again: If I save a YouTube link in my URLfield, it embeds the video in the frontend, but if I choose any other default provider it would just render nothing.
Any ideas, if I need to import or extend anything else in order to make embeds work?
THANKS
Maybe related: "How Embed Gist in Wagtail?"

Ok, so the problem got solved via the github issue thread.
The problem was not Wagtail related (but OSX / Python SSL certificate related), but I'll post the solution in case others might run into this too.
I had to go to the folder of my Python installation (/Python 3.7 in my case) and double click the file Install Certificates.command.
After that I restarted the server and the embed requests are now working fine and returning the expected result.

If you have limited the embed 'finders' in your settings (WAGTAILEMBEDS_FINDERS) then this would have the described effect.
http://docs.wagtail.io/en/v2.1.1/advanced_topics/embeds.html#customising-the-provider-list
The providers you have tried do appear to be represented in the default oembed finders list, so that shouldn't cause a problem.

Related

Python / Django render_to_string outpu rendered as text with html entities

I am porting a python / Django application from:
Django==1.5.1
python version 2.6.6
to
Django==3.2
python version 3.6.8
The issue that I am having is that I have a section of code that renders to string, a particular HTML template, and then adds that to list to output elsewhere.
The actual code that produces this HTML is:
class AccountAdmin(SmarterModelAdmin):
list_display = ('username', 'files_url', 'teamMembers', 'roleMemberships', 'safetyLimit', 'admin_quota', 'manager', 'enabled', 'path')
list_filter = ['enabled', 'manager', 'accountType']
search_fields = ['username']
inlines = [RolesInline]
valid_lookups = (
'members__member__username',
'teams__role__username',
)
roles = Account.objects.filter(teams__member=account).order_by('username')
roleList = []
for role in roles:
link = '/admin/files/account/?teams__role__username=' + role.username
# mylink = ''+role.username+''
# linkText = format_html(mylink,myurl=link)
linkText = render_to_string('common/contact.html', context={'URL': link, 'contact': role})
roleList.append(linkText)
return ', '.join(roleList)
roleMemberships.short_description='Roles'
roleMemberships.allow_tags=True```
I have added in a logging.warn to validate what comes out of the render_to_string, and it is straight HTML.
The commented out lines were something that I tried that fixed a similar issue.
common/contact.html is:
<a
href="{{ URL }}"
{% if not contact.enabled %}
style="text-decoration:line-through;"
{% endif %}
>{{ contact.username }}</a>
However, on the final render, It comes out like this:
<a href="/admin/files/account/?teams__role__username=abaumann"
>abaumann</a>,
abaumann
which when run through a browser looks like this:
I haven’t been able to find anything that references this particular issue. I have everything else working in the admin section of the django application, and I am at a loss for why it is not rendering as expected.
Please let me know if there is anything else that you need to see.
I was on the right track, just had an issue with implementation.
Django backend tries to make everything secure. As such, the generated HTML from my template was not considered safe. So, using the mark_safe() function was the key. But where to place it was the challenge.
Anytime the variable containing the HTML is modified IN ANY WAY, the "safe" flag is removed, and the variable is passed through encoding to render any HTML as text.
So the fixe is, on this line:
return ', '.join(roleList)
change it to:
return mark_safe(', '.join(roleList))
My mistake was placing the mark_safe on the linkText variable either at the time the vaiable was set, or when it was appended to the roleList.

django-easy-select2 Select2Multiple widget doesn't render

The installation page looked simple enough. I installed it, added easy_select2 in INSTALLED_APPS in the settings, ran collectstatic, and then had this in my form:
from easy_select2 import Select2Multiple
# from django_select2 import forms as select2_forms
class LeadForm(forms.Form):
email = forms.CharField(max_length=100)
overseas_company = forms.MultipleChoiceField(
choices=countries,
label='Do you have any companies overseas and where?',
widget=Select2Multiple()
)
But it still renders as if I had done nothing at all. I tried django_select2 as well, and it didn't work either, so I must be doing something wrong Select2 wise.
I tried looking at the HTTP request log. Merely enabling easy_select2 doesn't make the template request the jQuery/select2 js files that are needed for the Select2 widget to function. Is this the problem? But the tutorial never said I had to add anything to any existing templates.
I had the same problem too.
You have to add {{ form.media }} in the head section of your template for django to make it work.
source: http://do-it-big.com/getting-django-easy-select2-to-include-jquery-and-friends/

Django 1.8 - Can access var in base.html, but same variable empty when I extend into another page (articlePage.html)

I have a news article style site I'm building to learn Django. Anyways I've gotten everything working until I got to the sidebar. With the sidebar I have an issue. When I'm on the 'base.html' or the 'article.html' page the latest_article_list works and shows up. When I try to extend 'base.html' to 'articlePage.html' latest_article_list is an empty variable.
My question is how do I get it so that I can access latest_article_list in the 'articlePage.html', I have no problem accessing it in 'base.html' nor in 'article.html' which extends base.html. articlePage.html ALSO extends base.html but as I said, it won't work there.
Sidebar on article.html(my index) working as expected displaying 4 most recently added articles and a thumbnail
Sidebar on articlePage.html(page for each individual article) not displaying any recent articles, just my error msg
Does it have to do with the fact my article url's are dynamic and not static? I'm completely lost, so any help would be great.
I've provided a link to my repository.
The 'pip' installations I have for this project are: Django 1.8, Pillow 2.8.1 and VirtualEnv 12.1.1
https://github.com/kevinIN3D/articleTestProject
The first thing is that you declare block 'sidebarBlock' in base.html but you don't fill it with something neither in index.html nor in articlePage.html. It works in index.html because you send variable with your view. You cannot take any variables from your base.html. You should provide these in your ArticleView.
It should look like this:
class ArticleView(generic.DetailView):
model = Article
template_name = 'articles/articlePage.html'
def get_queryset(self):
self.latest_article_list = Article.objects.filter(
article_pub_date__lte=timezone.now()).order_by('-article_pub_date')[:4]
return Article.objects.filter(article_pub_date__lte=timezone.now())
def get_context_data(self, **kwargs):
context = super(ArticleView, self).get_context_data(**kwargs)
context['latest_article_list'] = self.latest_article_list
return context

Django send_mail application - hook it up with Yeoman frontend

I'm using Django as backend and Yeoman as frontend. I'm new to both. My frontend local server is running on localhost:9000, and my backend server is running on localhost:8000.
I just built an email sender application following the Django tutorial. It is working perfectly and consists of:
A form:
class ContactForm(forms.Form):
name = forms.CharField()
email = forms.EmailField()
telephoneNr = forms.IntegerField()
message = forms.CharField(widget=forms.Textarea)
A view:
from django.core.mail import send_mail
from django.shortcuts import render, render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from mailsender.forms import ContactForm
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
success = True
name = form.cleaned_data['name']
email = form.cleaned_data['email']
telephoneNr = form.cleaned_data['tlf']
message= form.cleaned_data['melding']
receiverEmail = ['somewhere#example.com']
text = message +'\n'+name +'\n'+str(telephoneNr)
send_mail('Contact form', beskjed, email, receiverEmail)
return render(request,"result.html")
else:
form = ContactForm(
return render(request, 'contactform.html', {'form':form})
And my HTML:
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_p }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</form>
If I visit localhost:8000/contactform, the contact form is displayed just as I want, and it does send emails.
I need help figuring out how to hook up this view to the Yeoman frontend - as searching the Internetz (and SO) leads me to the path of confusion. Should I use Tastypie? I really want to keep this logic in the backend. Any help pointing me in the right direction is greatly appreciated.
First off, you should consider not using Django templates & forms at all. (Supposing you're working on some bigger stuff)
Django is a really cool framework, but I found those 2 building blocks of it somewhat limited (https://stackoverflow.com/a/17383408/1432478).
The JS framework, that you use with Yeoman should take care of building HTML.
Django-Yeoman integration
Development architecture
Yeoman should serve html (templates replacement) and other static files + take care of JS framework of your choice.
If frontend needs to obtain/submit some data from/to the backend, it should issue a request to the very same server that is serving static content (Under the bonnet Yeoman is using Node.js as this server).
But wait ... how Node.js server is supposed to know about backend logic?
Yo can use grunt-connect-proxy to forward any request to another server - in this case Django.
I found this grunt-connect-proxy setup guide particularly helpful.
By issuing backend requests to the very same socket address (IP:port), you don't have to perform CORS or crazy stuff like parsing whole of your frontend code when building the production-ready version of your app in order to replace the socket address used in development with the one suitable for production.
Production & Deployment
When you run grunt it'll package production-ready version of your frontend static files in dist subdirectory.
Before submitting your django application as a package you basically copy htmls and the rest of the static content files to static/your_app.
I decided to serve Angular's htmls as static content - making them Django's templates would cause too much fuss (conflicting markup, static loaders, and so on ...).
When some django project (containing your django app) is deployed, the static files, that were in dev setup served by node, are going to be served by django.
In other words: in production you need only one server - the one used by django.
It's only during development, that you need to benefit from fuzzy-buzzy stuff offered by yeoman, such as:
LiveReload
linting your code
generators
...
Note: I've read that Yeoman team is planning on providing a better way of integrating yeoman with web frameworks. Not sure how they want to do it, perhaps a similar solution to generators (separate generator per framework).
Sample
Yo can check out a django app I'm currently working on: https://github.com/vucalur/django-wibses/
It uses Angular JS and above I just described the architecture of it :)
Note: It is so not-finished-yet :) But as of today development setup is done, except for CSRF protection.
Tastypie
We are considering using Tastypie in the mentioned app, but only when writing RESTful API manually will become arduous. So I think whether to use Tastypie or not is up to you.
Further reading
I based my setup on this.
But if you know something about Java web apps, you should take a look at those (I wanted my Django-Yeoman integration work similarly to how Java(Maven)-Yeoman integration works):
http://addyosmani.com/blog/making-maven-grunt/
https://github.com/trecloux/yeoman-maven-plugin (mentioned in Addy's post)
http://blog.tartachuc.org/2013/06/11/tomcat-maven-angular-grunt-et-yeoman-sont-dans-un-bateau/ (mentioned in Addy's post)
http://naleid.com/blog/2013/01/24/calling-gruntjs-tasks-from-gradle/
http://blog.tfnico.com/2013/07/considerations-for-javascript-in-modern.html (not directly related, but still worth reading)

get Django admin site to show pdfs

First, a little background: My healthcare office has a network drive on which we store all of our patient records. The default Windows Explorer interface does not provide enough data safety when accessing the network drive. Users are able to accidentally rename things, move things, name things improperly, etc. When this happens, it becomes very difficult to find records.
So, I am trying to fix that by designing an interface that is "safer." I decided to use Python and Django because - once the database is set up - it's actually much faster, and it would be nice to not have to install an application on every computer in the office - they just visit the internal web page. I've already designed the back end python code, which keeps the database synced with the network drive. It wasn't easy, but I was able to figure it out. However, now I have to design the front end, which lets the users update the database, and I'm not a web programmer, so the thought of learning advanced html, css, jquery, etc just for this one project was daunting. I also really like the way the Django Admin interface looked. Finally, it did mostly what I wanted it to do - provided an easy way to see what was there, and change that if necessary. So, I've decided to try and tweak the admin templates and such to get them to do what I want. There are a lot of issues I'm running into, but I've decided to make a separate question for each one, and this is the one I'm working on right now:
Each record is a pdf, and I'm looking at the InlineTab template and trying to get it to include a link to that pdf file on the local file system. I've got it to display a link, but when I click on it, nothing happens. Ideally, when I click on the link, I'd like it to show the pdf in a space set aside for that on the page (currently the information for each record goes across the whole screen, and I want it to only go partway across and have the rest of the screen show the pdf of the selected record), but for now I'd settle for getting the link to open on its own.
my models:
class Patient(models.Model):
"""Holds all the information needed for a Patient and their records"""
last_name = models.CharField(max_length = 100)
first_name = models.CharField(max_length = 100)
mid_init = models.CharField(max_length = 1, blank = True)
dob = models.CharField(max_length = 20, blank = True)
path = models.CharField(max_length = 500, blank = True)
class Record(models.Model):
"Holds all the information needed for a certain record"""
patient = models.ForeignKey(Patient)
title = models.CharField(max_length = 500)
created = models.CharField(max_length = 20, blank = True)
path = models.CharField(max_length = 200)
my "admin.py":
from django.contrib import admin
from records.models import Patient, Record
class RecordInline(admin.TabularInline):
model = Record
extra = 0
readonly_fields = ['path']
class PatientAdmin(admin.ModelAdmin):
fieldsets = [
('Patient Info', {'fields': ['last_name', 'first_name', 'mid_init', 'dob']}),
('Patient Folder', {'fields': ['path'], 'classes': ['collapse']}),
]
inlines = [RecordInline]
list_display = ('last_name', 'first_name', 'mid_init', 'dob')
search_fields = ('last_name', 'first_name', 'mid_init', 'dob')
admin.site.register(Patient, PatientAdmin)
You can see that the records are listed as a "tabular inline," so I tracked down that template (tabular.html), and this seems to be the relevant section of that template:
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
{% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %}
</p>{% endif %}
This just shows the name of the object, so I changed it to show a link to the actual path of that object thusly (the changed bit is in the "{% if inline_admin_form.original %} section):
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% if inline_admin_form.original %} {{ inline_admin_form.original.path }}{% endif %}
{% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %}
</p>{% endif %}
That definitely gave me a link to the file, but when I click it, nothing happens, and when I right-click and open it in a new tab, it just says "about:blank." What am I doing wrong?
UPDATE
Thanks in part to some research online, and ppetrid's answer below, I now know that my problem is that I'm trying to access a local file from a web server. Not being a web programmer, I didn't know that this would be a problem. Unfortunately, I'm not sure what the solution is.
I know that Django has a "File" object, and it seems like it would make sense to use that. However, disturbingly it looks as though each file added to the database that way will actually upload the file itself to a certain location. The problem is that we have literally thousands of files, exceeding 60GB in size, and basically duplicating that is not going to work. All I want is a pointer of sorts to the file, and the only "uploading" to happen when a person clicks on the link and sees the pdf in their browser. The files themselves are on the network in a DLink DNS-325 NAS device (the IP of which I can use in a url within Django). I've been accessing them through the Windows Map Network Drive, so they're also available under the "Z:/" drive on every workstation. Any way to get Django to just point to these files so I can see them in the browser?
UPDATE
I've found that Django itself has a way of serving "static" files of this type. Naturally, this is not suitable for "production," but I'll be using it to just get things working for now. I've followed the directions on the Django website about serving static files, and ended up with this in my settings.py:
STATIC_ROOT = 'C:/projects/working/'
STATIC_URL = '/static/'
The appropriate line of the tabular.html template now looks like this:
{% if inline_admin_form.original %} {{ inline_admin_form.original.relative_path }}{% endif %}
On the one hand, this seems to be working, because it's now trying to open a proper URL, but whenever it does, it gives me a 404 error, indicating the static file is not actually being served at that location. So, my NEW question is: how do I get the static files to actually be served at the correct URLs?
YET ANOTHER UPDATE
Ok, I think I've made a breakthrough. It seemed that although Django can serve static files, I wasn't doing all the steps necessary to make that happen. Now, my settings.py looks like this:
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'C:/projects/working/',
)
My urls.py looks like this:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^search_results/$', views.search_results),
)
urlpatterns += staticfiles_urlpatterns()
And the template for the tabular inline looks like this:
{% if inline_admin_form.original %} {{ inline_admin_form.original.relative_path }}{% endif %}
Now, this seems to be getting much closer to what I need. I don't get a 404, a "no object with that primary key exists", or the silent failure I got when I was pointing directly to a file on my hard drive. It actually opens a new page with the correct URL, Chrome says "loading" in the lower left (like it always does when opening a pdf), but it just sits there forever. It never actually loads. Any other ideas?
Why do you use a CharField for the "path" property? Since it's a file you should use a FileField to upload the pdf and then do href="{{inline_admin_form.original.path.url}}" to get a working link.
I would also change the name from "path" to "pdf" or something. The way you do it now you try to load the file directly from your local filesystem which won't work once you deploy your project (since the file won't be uploaded to the server). You might also want to have a look here https://docs.djangoproject.com/en/dev/topics/files/#using-files-in-models

Categories

Resources