ascroll for item/edits
This commit is contained in:
parent
bbae18bcf3
commit
21db49fe48
19 changed files with 348 additions and 75 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@ venv
|
||||||
__pycache__
|
__pycache__
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
www/
|
www/
|
||||||
|
*.swp
|
||||||
|
venv
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
.films {
|
.films {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
margin: 8px;
|
||||||
.film {
|
.film {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
margin-bottom: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
.left, .right {
|
.left, .right {
|
||||||
|
@ -34,3 +36,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.film {
|
||||||
|
.info {
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
.play {
|
||||||
|
text-align: center;
|
||||||
|
margin: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
8
app/static/css/partials/_text.scss
Normal file
8
app/static/css/partials/_text.scss
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
.texts {
|
||||||
|
.text {
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,4 +2,5 @@
|
||||||
@import "partials/layout";
|
@import "partials/layout";
|
||||||
@import "partials/burger";
|
@import "partials/burger";
|
||||||
@import "partials/film";
|
@import "partials/film";
|
||||||
|
@import "partials/text";
|
||||||
@import "partials/ascroll";
|
@import "partials/ascroll";
|
||||||
|
|
|
@ -31,12 +31,15 @@ function updatePlayerPosition(video, lastKnownScrollPosition) {
|
||||||
video.style.display = 'block';
|
video.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePlayer(video, frame, currentTime) {
|
function updatePlayer(video, frame, currentTime, src) {
|
||||||
var rect = frame.getBoundingClientRect();
|
var rect = frame.getBoundingClientRect();
|
||||||
video.style.opacity = 0
|
video.style.opacity = 0
|
||||||
console.log('update player', rect)
|
console.log('update player', rect)
|
||||||
video.style.top = (rect.top + window.scrollY) + 'px'
|
video.style.top = (rect.top + window.scrollY) + 'px'
|
||||||
video.style.display = 'block';
|
video.style.display = 'block';
|
||||||
|
if (src) {
|
||||||
|
video.src = src
|
||||||
|
}
|
||||||
//video.poster = frame.querySelector('img').src
|
//video.poster = frame.querySelector('img').src
|
||||||
video.currentTime = currentTime
|
video.currentTime = currentTime
|
||||||
video.controls = true
|
video.controls = true
|
||||||
|
@ -67,15 +70,15 @@ function onVisibilityChange(el, callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadItem(config) {
|
||||||
pandoraAPI('get', {id: film.id, keys: ['id', 'title', 'layers']}).then(response => {
|
pandoraAPI('get', {id: config.item, keys: ['id', 'title', 'layers']}).then(response => {
|
||||||
var ascroll = document.querySelector('#ascroll')
|
var ascroll = document.querySelector('#ascroll')
|
||||||
var loaded = false
|
var loaded = false
|
||||||
|
|
||||||
var video = document.createElement('video')
|
var video = document.createElement('video')
|
||||||
video.classList.add('player')
|
video.classList.add('player')
|
||||||
video.muted = true
|
video.muted = true
|
||||||
video.src = `${baseURL}/${film.id}/480p.webm`
|
video.src = `${baseURL}/${config.item}/480p.webm`
|
||||||
ascroll.appendChild(video)
|
ascroll.appendChild(video)
|
||||||
|
|
||||||
var h1 = document.createElement('h1')
|
var h1 = document.createElement('h1')
|
||||||
|
@ -83,6 +86,9 @@ pandoraAPI('get', {id: film.id, keys: ['id', 'title', 'layers']}).then(response
|
||||||
ascroll.appendChild(h1)
|
ascroll.appendChild(h1)
|
||||||
|
|
||||||
response.data.layers[layer].forEach(annotation => {
|
response.data.layers[layer].forEach(annotation => {
|
||||||
|
if (config.user && annotation.user != config.user) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var div = document.createElement('div')
|
var div = document.createElement('div')
|
||||||
div.classList.add('annotation')
|
div.classList.add('annotation')
|
||||||
div.innerHTML = `
|
div.innerHTML = `
|
||||||
|
@ -119,3 +125,77 @@ pandoraAPI('get', {id: film.id, keys: ['id', 'title', 'layers']}).then(response
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
function loadEdit(config) {
|
||||||
|
pandoraAPI('getEdit', {id: config.edit, keys: []}).then(response => {
|
||||||
|
console.log(response)
|
||||||
|
var ascroll = document.querySelector('#ascroll')
|
||||||
|
var loaded = false
|
||||||
|
|
||||||
|
var video = document.createElement('video')
|
||||||
|
video.classList.add('player')
|
||||||
|
video.muted = true
|
||||||
|
/*
|
||||||
|
video.src = `${baseURL}/${config.item}/480p.webm`
|
||||||
|
*/
|
||||||
|
ascroll.appendChild(video)
|
||||||
|
|
||||||
|
var h1 = document.createElement('h1')
|
||||||
|
var first
|
||||||
|
h1.innerHTML = response.data.name
|
||||||
|
ascroll.appendChild(h1)
|
||||||
|
|
||||||
|
response.data.clips.forEach(clip => {
|
||||||
|
clip.layers[layer].forEach(annotation => {
|
||||||
|
if (config.user && annotation.user != config.user) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!first) {
|
||||||
|
first = annotation
|
||||||
|
}
|
||||||
|
var div = document.createElement('div')
|
||||||
|
div.classList.add('annotation')
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="frame"><img src="${baseURL}/${annotation.id.split('/')[0]}/${imageResolution}p${annotation.in}.jpg"></div>
|
||||||
|
<div class="text">${annotation.value}</div>
|
||||||
|
|
||||||
|
`
|
||||||
|
ascroll.appendChild(div)
|
||||||
|
var frame = div.querySelector('.frame')
|
||||||
|
document.addEventListener('scroll', onVisibilityChange(div.querySelector('.frame'), function(visible) {
|
||||||
|
var src = `${baseURL}/${annotation.id.split('/')[0]}/480p.webm`
|
||||||
|
if (loaded && visible)
|
||||||
|
updatePlayer(video, frame, annotation['in'], src)
|
||||||
|
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
loaded = true
|
||||||
|
let frame = ascroll.querySelector('.annotation .frame')
|
||||||
|
if (frame) {
|
||||||
|
var src = `${baseURL}/${ifrst.id.split('/')[0]}/480p.webm`
|
||||||
|
updatePlayer(video, frame, first['in'], src)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
document.addEventListener('scroll', function(e) {
|
||||||
|
lastKnownScrollPosition = window.scrollY;
|
||||||
|
|
||||||
|
if (!ticking) {
|
||||||
|
window.requestAnimationFrame(function() {
|
||||||
|
updatePlayerPosition(video, lastKnownScrollPosition);
|
||||||
|
ticking = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
ticking = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.item) {
|
||||||
|
loadItem(config)
|
||||||
|
} else if (config.edit) {
|
||||||
|
loadEdit(config)
|
||||||
|
}
|
||||||
|
|
|
@ -13,16 +13,14 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="topnav">
|
<div class="topnav">
|
||||||
<a href="/" class="active">
|
<a href="/polis" class="active">
|
||||||
phtantasmapolis: Looking Back to the Future
|
phtantasmapolis: Looking Back to the Future
|
||||||
<br>
|
<br>
|
||||||
未竟之城:回顧未來
|
未竟之城:回顧未來
|
||||||
</a>
|
</a>
|
||||||
<nav>
|
<nav>
|
||||||
<a href="{% url 'films'%}">films - 影片</a>
|
<a href="{% url 'films'%}">films - 影片</a>
|
||||||
<a href="{% url 'edits' %}">edits - 編輯</a>
|
<a href="{% url 'texts' %}">assemblies - </a>
|
||||||
<a href="{% url 'tv' %}">tv - 頻道</a>
|
|
||||||
<a href="{% url 'essays' %}">essays - 專文</a>
|
|
||||||
<a href="{% url 'about' %}">about - 關於</a>
|
<a href="{% url 'about' %}">about - 關於</a>
|
||||||
</nav>
|
</nav>
|
||||||
<a class="icon">
|
<a class="icon">
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block main %}
|
|
||||||
some overview page with stuff
|
|
||||||
{% endblock %}
|
|
90
app/templates/fallback.html
Normal file
90
app/templates/fallback.html
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: "wrong font";
|
||||||
|
src: url("https://files.pad.ma/ttf/wrongfont.woff") format("woff");
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-family: "wrong font";
|
||||||
|
margin: auto;
|
||||||
|
font-weight: normal;
|
||||||
|
color: yellow;
|
||||||
|
font-size: 66px;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #6666ff;
|
||||||
|
font-family: "wrong font";
|
||||||
|
}
|
||||||
|
#box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: "wrong font";
|
||||||
|
overflow: hidden;
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#shadowBox {
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
/* Fallback color */
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
/* Black w/opacity/see-through */
|
||||||
|
border: 3px solid;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rainbow_text_animated {
|
||||||
|
background: linear-gradient(to right, #6666ff, #0099ff , #00ff00, #ff3399, #6666ff);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
animation: rainbow_animation 6s ease-in-out infinite;
|
||||||
|
background-size: 400% 100%;
|
||||||
|
}
|
||||||
|
.reflection {
|
||||||
|
transform: scaley(-1);
|
||||||
|
opacity: 0.3;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rainbow_animation {
|
||||||
|
0%,100% {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
background-position: 100% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<title>phantas.ma</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="box">
|
||||||
|
<div id="shadowBox">
|
||||||
|
<h1 class="rainbow rainbow_text_animated">Phantas.ma</h1>
|
||||||
|
<h2></h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
path = document.location.pathname.slice(1)
|
||||||
|
if (path) {
|
||||||
|
document.querySelector('h1').innerHTML = 'Phantas.ma/' + path
|
||||||
|
if (path == 'polis') {
|
||||||
|
setTimeout(() => {
|
||||||
|
document.querySelector('h2').innerHTML = 'Oct 30, 2021 – Mar 6, 2022'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,21 +1,23 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<video src="{{ settings.TIMELINE_PREFIX }}{{ film.padma_id }}/loop.mp4" autoplay loop muted></video>
|
<div class="film">
|
||||||
|
<div class="info">
|
||||||
|
|
||||||
<h1>{{ film.data.title | safe }}</h1>
|
<h1>{{ film.data.title | safe }}</h1>
|
||||||
<h2>{{ film.data.director|join:", "|safe }}</h2>
|
<h2>{{ film.data.director|join:", "|safe }}</h2>
|
||||||
<p>{{ film.data.summary|safe }}</p>
|
<p>{{ film.data.summary|safe }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<video src="{{ settings.TIMELINE_PREFIX }}{{ film.padma_id }}/loop.mp4" autoplay loop muted></video>
|
||||||
|
<div class="play">
|
||||||
<div>
|
<div>
|
||||||
<a href="" id="play-fullscreen">Watch Fullscreen</a>
|
<a href="" id="play-fullscreen">Watch Fullscreen</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% for text in film.related_texts %}
|
||||||
<div>
|
<div>
|
||||||
<a href="play/en">Watch with Annotations</a>
|
<a href="{{ text.get_absolute_url }}">{{ text.title }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
{% endfor %}
|
||||||
<a href="play/zh">Watch with Annotations (Mandarin title)</a>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,14 @@
|
||||||
<h1><a href="{% url 'film' film.slug %}">{{ film.data.title | safe }}</a></h1>
|
<h1><a href="{% url 'film' film.slug %}">{{ film.data.title | safe }}</a></h1>
|
||||||
<h2>{{ film.data.director|join:", "|safe }}</h2>
|
<h2>{{ film.data.director|join:", "|safe }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
{% comment %}
|
||||||
<div class="right">
|
<div class="right">
|
||||||
|
|
||||||
<a href="{% url 'film' film.slug %}">
|
<a href="{% url 'film' film.slug %}">
|
||||||
<img src="{{ settings.TIMELINE_PREFIX }}{{ film.padma_id }}/timeline.jpg">
|
<img src="{{ settings.TIMELINE_PREFIX }}{{ film.padma_id }}/timeline.jpg">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% endcomment %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
some overview page with stuff
|
<div>
|
||||||
|
<div>
|
||||||
|
Phantas.ma/polis is mainly in support by the Cultural Taiwan Foundation and in cooperation with SEA plateaus
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
本計畫由財團法人文化臺灣基金會支持、SEA plateaus協力
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
10
app/templates/text.html
Normal file
10
app/templates/text.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block main %}
|
||||||
|
<div id="ascroll"></div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block end %}
|
||||||
|
<script>
|
||||||
|
var config = {{ text.json | safe }};
|
||||||
|
</script>
|
||||||
|
<script src="/static/js/ascroll.js"></script>
|
||||||
|
{% endblock %}
|
10
app/templates/texts.html
Normal file
10
app/templates/texts.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<div class="texts">
|
||||||
|
{% for text in texts %}
|
||||||
|
<div class="text">
|
||||||
|
<a href="{{ text.get_absolute_url }}">{{ text.title }}</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
|
@ -1,3 +1,12 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
# Register your models here.
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
@admin.decorators.register(models.Text)
|
||||||
|
class TextAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@admin.decorators.register(models.Page)
|
||||||
|
class PageAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
17
app/text/migrations/0002_rename_essay_text.py
Normal file
17
app/text/migrations/0002_rename_essay_text.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-10-10 14:25
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('text', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='Essay',
|
||||||
|
new_name='Text',
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,5 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
@ -19,15 +21,27 @@ class Page(models.Model):
|
||||||
teaser = models.TextField()
|
teaser = models.TextField()
|
||||||
body = models.TextField()
|
body = models.TextField()
|
||||||
|
|
||||||
class Essay(models.Model):
|
class Text(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
slug = models.SlugField()
|
slug = models.SlugField()
|
||||||
public = models.BooleanField(default=False)
|
public = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
title = models.TextField()
|
||||||
|
teaser = models.TextField(default="", blank=True)
|
||||||
|
body = models.TextField(default="", blank=True)
|
||||||
|
|
||||||
data = models.JSONField(default=dict)
|
data = models.JSONField(default=dict)
|
||||||
|
|
||||||
title = models.TextField()
|
def __str__(self):
|
||||||
teaser = models.TextField()
|
return self.title
|
||||||
body = models.TextField()
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return '/' + settings.URL_PREFIX + 'assemblies/' + self.slug
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
data = {}
|
||||||
|
data['title'] = self.title
|
||||||
|
data.update(self.data)
|
||||||
|
return json.dumps(data)
|
||||||
|
|
|
@ -2,6 +2,10 @@ from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
def fallback(request):
|
||||||
|
context = {}
|
||||||
|
return render(request, 'fallback.html', context)
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
context = {}
|
context = {}
|
||||||
return render(request, 'index.html', context)
|
return render(request, 'index.html', context)
|
||||||
|
@ -10,12 +14,12 @@ def about(request):
|
||||||
context = {}
|
context = {}
|
||||||
return render(request, 'about.html', context)
|
return render(request, 'about.html', context)
|
||||||
|
|
||||||
def essays(request):
|
def texts(request):
|
||||||
context = {}
|
context = {}
|
||||||
context['essays'] = models.Essay.objects.filter(public=True).order_by('created')
|
context['texts'] = models.Text.objects.filter(public=True).order_by('created')
|
||||||
return render(request, 'essays.html', context)
|
return render(request, 'texts.html', context)
|
||||||
|
|
||||||
def essay(request, slug, lang):
|
def text(request, slug):
|
||||||
context = {}
|
context = {}
|
||||||
context['essay'] = get_object_or_404(models.Essay, slug=slug)
|
context['text'] = get_object_or_404(models.Text, slug=slug)
|
||||||
return render(request, 'essay.html', context)
|
return render(request, 'text.html', context)
|
||||||
|
|
|
@ -30,9 +30,10 @@ urlpatterns = [
|
||||||
path(settings.URL_PREFIX + 'edit/<str:slug>/play/<str:lang>', video.edit_play, name='edit_play'),
|
path(settings.URL_PREFIX + 'edit/<str:slug>/play/<str:lang>', video.edit_play, name='edit_play'),
|
||||||
path(settings.URL_PREFIX + 'edit/<str:slug>/', video.edit, name='edit'),
|
path(settings.URL_PREFIX + 'edit/<str:slug>/', video.edit, name='edit'),
|
||||||
path(settings.URL_PREFIX + 'tv/', video.tv, name='tv'),
|
path(settings.URL_PREFIX + 'tv/', video.tv, name='tv'),
|
||||||
path(settings.URL_PREFIX + 'essays/', text.essays, name='essays'),
|
path(settings.URL_PREFIX + 'assemblies/', text.texts, name='texts'),
|
||||||
path(settings.URL_PREFIX + 'essay/<str:slug>/<str:lang>', text.essay, name='essay'),
|
path(settings.URL_PREFIX + 'assemblies/<str:slug>', text.text, name='text'),
|
||||||
path(settings.URL_PREFIX + 'about/', text.about, name='about'),
|
path(settings.URL_PREFIX + 'about/', text.about, name='about'),
|
||||||
|
|
||||||
path(settings.URL_PREFIX[:-1], text.index, name='index'),
|
path(settings.URL_PREFIX[:-1], text.index, name='index'),
|
||||||
|
path('', text.fallback, name='fallback'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -22,6 +22,13 @@ class Film(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.data.get('title', self.slug)
|
return self.data.get('title', self.slug)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return '/' + settings.URL_PREFIX + 'film/' + self.slug
|
||||||
|
|
||||||
|
def related_texts(self):
|
||||||
|
from ..text.models import Text
|
||||||
|
return Text.objects.filter(data__item=self.padma_id)
|
||||||
|
|
||||||
|
|
||||||
class Edit(models.Model):
|
class Edit(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
Loading…
Reference in a new issue