diff options
Diffstat (limited to 'app/posts')
24 files changed, 539 insertions, 203 deletions
diff --git a/app/posts/admin.py b/app/posts/admin.py index 5a51f44..1153e81 100644 --- a/app/posts/admin.py +++ b/app/posts/admin.py @@ -4,7 +4,7 @@ from django.contrib.gis.admin import OSMGeoAdmin from django.contrib.contenttypes.admin import GenericStackedInline from utils.widgets import AdminImageWidget, LGEntryForm -from .models import Post, Trip +from .models import Post, Trip, Guide from media.models import LuxImage from utils.util import get_latlon @@ -34,7 +34,7 @@ class PostAdmin(OSMGeoAdmin): field = super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs) return field - list_display = ('title', 'site', 'post_type', 'pub_date', 'template_name', 'status',) + list_display = ('title', 'site', 'post_type', 'pub_date', 'status',) search_fields = ['title', 'body_markdown'] prepopulated_fields = {"slug": ('title',)} list_filter = ('site', 'post_type', 'pub_date', 'enable_comments', 'status') @@ -45,12 +45,11 @@ class PostAdmin(OSMGeoAdmin): ('title', 'short_title'), ('subtitle', 'trip'), 'body_markdown', - ('pub_date', 'status', 'post_type'), + ('pub_date', 'status', 'post_type', 'post_topic'), ('slug', 'enable_comments',), 'point', 'dek', 'meta_description', - 'template_name', ('featured_image','related'), 'site' ), @@ -126,3 +125,38 @@ class TripAdmin(OSMGeoAdmin): css = { "all": ("my_styles.css",) } + + +@admin.register(Guide) +class GuideAdmin(OSMGeoAdmin): + form = LGEntryForm + list_display = ('title', 'is_featured', 'slug' ) + prepopulated_fields = {'slug': ('title',)} + search_fields = ('title',) + filter_horizontal = ('posts',) + fieldsets = ( + ('', { + 'fields': ( + 'title', + 'subtitle', + 'seo_title', + 'body_markdown', + 'posts', + ('slug', 'status'), + 'dek', + 'meta_description', + 'featured_image', + ('is_featured', 'related') + ), + 'classes': ( + 'show', + 'extrapretty' + ) + }), + ) + + class Media: + js = ('image-loader.js', 'next-prev-links.js') + css = { + "all": ("my_styles.css",) + } diff --git a/app/posts/migrations/0025_guide.py b/app/posts/migrations/0025_guide.py new file mode 100644 index 0000000..636e2cd --- /dev/null +++ b/app/posts/migrations/0025_guide.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2.7 on 2024-02-25 10:20 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('media', '0008_auto_20201202_1155'), + ('posts', '0024_alter_trip_options_trip_dek'), + ] + + operations = [ + migrations.CreateModel( + name='Guide', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('subtitle', models.CharField(blank=True, max_length=200)), + ('seo_title', models.CharField(blank=True, max_length=200)), + ('slug', models.SlugField()), + ('body_markdown', models.TextField()), + ('body_html', models.TextField(blank=True)), + ('dek', models.TextField(blank=True, null=True)), + ('meta_description', models.CharField(blank=True, max_length=256)), + ('last_updated', models.DateTimeField(auto_now=True)), + ('is_featured', models.BooleanField(blank=True, default=False)), + ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Published')], default=0)), + ('featured_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='media.luximage')), + ('posts', models.ManyToManyField(blank=True, to='posts.post')), + ], + options={ + 'ordering': ('-last_updated',), + 'get_latest_by': 'last_updated', + }, + ), + ] diff --git a/app/posts/migrations/0026_guide_related.py b/app/posts/migrations/0026_guide_related.py new file mode 100644 index 0000000..11f0e56 --- /dev/null +++ b/app/posts/migrations/0026_guide_related.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.7 on 2024-02-25 10:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('normalize', '0004_relatedpost_post_type'), + ('posts', '0025_guide'), + ] + + operations = [ + migrations.AddField( + model_name='guide', + name='related', + field=models.ManyToManyField(blank=True, to='normalize.relatedpost'), + ), + ] diff --git a/app/posts/migrations/0027_remove_post_template_name_post_post_topic.py b/app/posts/migrations/0027_remove_post_template_name_post_post_topic.py new file mode 100644 index 0000000..43dda71 --- /dev/null +++ b/app/posts/migrations/0027_remove_post_template_name_post_post_topic.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.7 on 2024-02-25 11:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('posts', '0026_guide_related'), + ] + + operations = [ + migrations.RemoveField( + model_name='post', + name='template_name', + ), + migrations.AddField( + model_name='post', + name='post_topic', + field=models.IntegerField(choices=[(0, 'spirit'), (1, 'craft'), (2, 'tools')], default=0), + ), + ] diff --git a/app/posts/models.py b/app/posts/models.py index 2ad995d..2726949 100644 --- a/app/posts/models.py +++ b/app/posts/models.py @@ -76,6 +76,12 @@ class PostType(models.IntegerChoices): FIELD_NOTE = 5, ('field note') GUIDE = 6, ('guide') FILM = 7, ('film') + HOWTO = 8, ('how to') + +class PostTopic(models.IntegerChoices): + SPIRIT = 0, ('spirit') + CRAFT = 1, ('craft') + TOOLS = 2, ('tools') class Post(models.Model): @@ -101,16 +107,8 @@ class Post(models.Model): ) status = models.IntegerField(choices=PUB_STATUS, default=0) featured_image = models.ForeignKey(LuxImage, on_delete=models.SET_NULL, null=True, blank=True) - TEMPLATES = ( - (0, 'single'), - (1, 'double'), - (2, 'single-dark'), - (3, 'double-dark'), - (4, 'single-black'), - (5, 'double-black'), - ) post_type = models.IntegerField(choices=PostType.choices, default=PostType.JRNL) - template_name = models.IntegerField(choices=TEMPLATES, default=0) + post_topic = models.IntegerField(choices=PostTopic.choices, default=PostTopic.SPIRIT) has_video = models.BooleanField(blank=True, default=False) has_code = models.BooleanField(blank=True, default=False) disclaimer = models.BooleanField(blank=True, default=False) @@ -138,15 +136,12 @@ class Post(models.Model): return reverse('film:detail', kwargs={"slug": self.slug}) if self.post_type == PostType.ESSAY: return reverse('essays:detail', kwargs={"slug": self.slug}) - if self.post_type == PostType.RANGE: - m = NewsletterMailing.objects.get(post__id=self.pk) - return reverse('range:range-detail', kwargs={"issue": m.get_issue_str(), "slug": self.slug}) if self.post_type == PostType.SRC: return reverse('src:detail', kwargs={"slug": self.slug}) if self.post_type == PostType.FIELD_NOTE: return reverse('fieldnote:detail', kwargs={"year": self.pub_date.year, "month": self.pub_date.strftime("%m"), "slug": self.slug}) if self.post_type == PostType.GUIDE: - return reverse('guides:guide-detail', kwargs={"topic": str(self.topics.all()[0]).lower(), "slug": self.slug}) + return reverse('guides:guide-post-detail', kwargs={"topic": self.guide_set.all()[0].slug, "slug": self.slug}) if self.post_type == PostType.JRNL: return reverse('jrnl:detail', kwargs={"year": self.pub_date.year, "month": self.pub_date.strftime("%m"), "slug": self.slug}) @@ -264,6 +259,38 @@ class PostModerator(CommentModerator): return True moderator.register(Post, PostModerator) + +class Guide(models.Model): + title = models.CharField(max_length=200) + subtitle = models.CharField(max_length=200, blank=True) + seo_title = models.CharField(max_length=200, blank=True) + slug = models.SlugField() + body_markdown = models.TextField() + body_html = models.TextField(blank=True) + dek = models.TextField(null=True, blank=True) + meta_description = models.CharField(max_length=256, blank=True) + last_updated = models.DateTimeField(auto_now=True) + is_featured = models.BooleanField(blank=True, default=False) + PUB_STATUS = ( + (0, 'Draft'), + (1, 'Published'), + ) + status = models.IntegerField(choices=PUB_STATUS, default=0) + featured_image = models.ForeignKey(LuxImage, on_delete=models.SET_NULL, null=True, blank=True) + posts = models.ManyToManyField(Post, blank=True) + related = models.ManyToManyField(RelatedPost, blank=True) + + class Meta: + ordering = ('-last_updated',) + get_latest_by = 'last_updated' + + def __str__(self): + return self.title + + def get_absolute_url(self): + return reverse('guides:guide-detail', kwargs={"slug": self.slug}) + + @receiver(comment_was_posted, sender=Comment) def cache_gravatar(sender, comment, **kwargs): gravatar_exists = has_gravatar(comment.email) diff --git a/app/posts/templates/posts/essay_detail.html b/app/posts/templates/posts/essay_detail.html index 42d06a2..7380c7e 100644 --- a/app/posts/templates/posts/essay_detail.html +++ b/app/posts/templates/posts/essay_detail.html @@ -14,15 +14,15 @@ <header id="header" class="post-header"> <h1 class="p-name post-title" itemprop="headline">{{object.title|smartypants|safe}}</h1> {% if object.subtitle %}<h2 class="post-subtitle">{{object.subtitle|smartypants|safe}}</h2>{%endif%} - <div class="post-dateline"> - {% if object.originally_published_by %}<h4 class="post-source">Originally Published By: <a href="{{object.originally_published_by_url}}" title="View {{object.title}} on {{object.originally_published_by}}">{{object.originally_published_by}}</a></h4>{%endif%} - {% if object.location %}<div class="p-location h-adr adr post-location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place"> + <div class="post-dateline"><time class="dt-published published dt-updated post-date" style="display:inline" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"Y"}}</span></time> – + {% if object.location %}<div class="p-location h-adr adr post-location" style="display:inline" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place"> <span class="h-adr" itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">{% if object.location.country_name == "United States" %} <span class="p-locality locality" itemprop="addressLocality">{{object.location.name|smartypants|safe}}</span>, <span class="p-region region">{{object.location.state_name|safe}}</span><span class="p-country-name" itemprop="addressCountry"></span>{%else%} <span class="p-region" itemprop="addressRegion">{{object.location.name|smartypants|safe}}</span>, <span class="p-country-name country-name"><span itemprop="addressCountry">{{object.location.country_name|safe}}</span></span>{%endif%} </span> </div>{%endif%} - <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time> + <div>Filed under: <a href="/essays/">{{object.get_post_topic_display}}</a></div> + {% if object.originally_published_by %}<h4 class="post-source">Originally Published By: <a href="{{object.originally_published_by_url}}" title="View {{object.title}} on {{object.originally_published_by}}">{{object.originally_published_by}}</a></h4>{%endif%} <span class="hide" itemprop="author" itemscope itemtype="http://schema.org/Person">by <a class="p-author h-card" href="/about"><span itemprop="name">Scott Gilbertson</span></a></span> </div> </header> diff --git a/app/posts/templates/posts/essay_list.html b/app/posts/templates/posts/essay_list.html index 6c9820d..0b516a6 100644 --- a/app/posts/templates/posts/essay_list.html +++ b/app/posts/templates/posts/essay_list.html @@ -3,11 +3,10 @@ {% block pagetitle %}Notes and Essays On Living - By Scott Gilbertson {% endblock %} {% block metadescription %}Essays and stories on self-reliance, DIY, repair, tools, birding, walking, living well, and other ephemera.{% endblock %} {% block breadcrumbs %}{% if breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{%endif%}{% endblock %} -{% block primary %}<main class="archive-wrapper"> +{% block primary %}<main role="main" id="essay-archive" class="essay-archive archive-list"> <div class="archive-intro"> - <h1 class="archive-sans">Notes & Essays</h1> - <p><em>Être fort pour être utile</em></p> - <p>Essays and stories on self-reliance, DIY, repair, tools, birding, walking, living well, and other bric-à-brac. Please, enjoy.</p> + <h1>Spirit</h1> + <h3>Once Spirit meant "breath of a god," and therefore "inspiration; breath of life," hence life itself. Spirit animates us and everything we do; the why behind the what and how.</h3> </div> <ul class="archive-list">{% for object in object_list %} <li class="h-entry hentry archive-list-card archive-list-card-sm" itemscope itemType="http://schema.org/Article"> diff --git a/app/posts/templates/posts/guide_base.html b/app/posts/templates/posts/guide_base.html index aef4cf0..d8ccc98 100644 --- a/app/posts/templates/posts/guide_base.html +++ b/app/posts/templates/posts/guide_base.html @@ -2,28 +2,28 @@ {% load typogrify_tags %} {% load html5_datetime %} {% load pagination_tags %} -{% block pagetitle %}Advice, Tools, Tips, and Tricks for Full Time Van or RV Life.{% endblock %} -{% block metadescription %}Guides for fellow travelers: tools, tips, and tricks to make life on the road in an RV or Van easier and more enjoyable.{% endblock %} +{% block pagetitle %}Advice, Tools, Tips, and Tricks.{% endblock %} +{% block metadescription %}{% endblock %} {% block primary %} <main role="main" id="guide-archive" class="archive-list"> <div class="archive-intro"> - <h2 class="post-title">Guides and How-Tos</h2> - <h3 class="post-subtitle">Advice, Tools, Tips, and Tricks for Life.</h3> + <h1 class="post-title">Guides and How-Tos</h1> + <h2 class="post-subtitle">Advice, Tools, Tips, and Tricks for Life.</h2> <p>I don't know how many of these I'll do, but I wanted to have a place to share some things I've learned, so I made this page. So far, just some thoughts on photography and how to use the Darktable image editor.</p> {%comment%}<p>I don't want to tell you how to travel. Everyone is different. Besides, even after twenty some odd years of travel, I am still learning. </p> <p>I've always been most inspired by wandering monks and nuns, those who walked or sailed with next to nothing and survived. Mostly. Today most of us are not that skilled or strong of will, but keeping that example in mind is helpful. The less stuff you travel with the better off you are. Up to a point. Having the right tools is important. The right tools make life easier and more fun.</p> <p>I put this together to help you find the tools you need. These aren't casual reviews. These are things I have spent years seeking out, using, and refining. In the end what you need are not things, but strategies and tools that allow you to create solutions to problems. </p>{%endcomment%} </div> - <ul class="archive-list"> + <ul class="archive-list">{% for object in object_list %} <li class="h-entry hentry archive-list-card archive-list-card-sm" itemscope itemType="http://schema.org/Article"> <span class="date dt-published card-smcaps">{% now "F Y" %}</span> - <a href="/guide/photography/"> - <h2 class="card-hed">Photography</h2> - <p class="p-summary card-lede">Thoughts on photography and how to edit images with Darktable</p> + <a href="{{object.get_absolute_url}}"> + <h2 class="card-hed">{{object.title}}</h2> + <p class="p-summary card-lede">{{object.dek}}</p> </a> - </li> + </li>{%endfor%} </ul> {% comment %} {% autopaginate object_list 30 %} diff --git a/app/posts/templates/posts/guide_detail.html b/app/posts/templates/posts/guide_detail.html index af0e649..28ff563 100644 --- a/app/posts/templates/posts/guide_detail.html +++ b/app/posts/templates/posts/guide_detail.html @@ -18,87 +18,26 @@ <meta itemprop="position" content="1" /> </span> <span class="nav-item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"> - <a href="{% url 'guides:guide-base' %}" itemprop="name">Guides</a> + <a href="{% url 'guides:guide-list' %}" itemprop="name">Guides</a> <meta itemprop="position" content="2" /> </span> <span class="nav-item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"> - <span itemprop="name">{{topic}}</span> + <span itemprop="name">{{object.title}}</span> <meta itemprop="position" content="3" /> </span> </nav> {% endblock %} {% block primary %}<main> - <article class="h-entry hentry entry-content content" itemscope itemType="http://schema.org/BlogPosting"> - <header id="header" class="post-header"> - <h1 class="p-name post-title" itemprop="headline">{{object.title|smartypants|safe}}</h1> - {% if object.subtitle %}<h2 class="post-subtitle">{{object.subtitle|smartypants|safe}}</h2>{%endif%} - <div class="post-dateline"> - {% if object.location %}<div class="p-location h-adr adr post-location"> - <span class="h-adr">{% if object.location.country_name == "United States" %} - <span class="p-locality locality">{{object.location.name|smartypants|safe}}</span>, <a class="p-region region" href="/jrnl/united-states/" title="travel writing from the United States">{{object.location.state_name|safe}}</a>, <span class="p-country-name">U.S.</span>{%else%} - <span class="p-region">{{object.location.name|smartypants|safe}}</span>, <a class="p-country-name country-name" href="/jrnl/{{object.location.country_slug}}/" title="travel writing from {{object.location.country_name}}">{{object.location.country_name|safe}}</a>{%endif%} - </span> - – <span id="mapbtn" data-clat="{{object.latitude}}" data-clon="{{object.longitude}}" data-type="point" data-latitude="{{object.latitude}}" data-longitude="{{object.longitude}}">Map</a> - </div>{%endif%} - <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time> - <span class="hide">by <a class="p-author h-card" href="/about">Scott Gilbertson</a></span> - </div> - </header> - <div class="e-content entry-content post-body" itemprop="articleBody"> - {% if object.prologue_html %}<div class="post-afterward "> - {{object.prologue_html|smartypants|safe}} - </div><hr />{%endif%} - {{object.body_html|safe|smartypants}} - </div> - <div class="entry-footer"> - <aside> - <h4>This is part of a series of posts on {{topic|lower}}, you can <a href="{% url 'guides:guides-by-topic' topic|lower %}">read the rest here</a>.</h4> - </aside> + <div class="archive-list">{% for object in object.posts.all %} + <article class="h-entry hentry archive-list-card archive-list-card-sm" itemscope itemType="http://schema.org/Article"> + <span class="date dt-published card-smcaps">{{object.pub_date|date:"F Y"}}</span> + <a href="{{object.get_absolute_url}}"> + <h2 class="card-hed">{{object.title|safe|smartypants|widont}}</h2> + <h3 class="p-summary card-lede">{% if object.subtitle %}{{object.subtitle|safe|smartypants|widont}}{%endif%}</h3> + </a> + <span class="card-smcaps">Filed Under: {{object.get_post_topic_display}}</span> + </article>{%endfor%} </div> - </article> - {% if object.related.all %}<div class="article-afterward related"> - <div class="related-bottom"> - <h6 class="hedtinycaps">You might also enjoy</h6> - <div class="archive-grid-quad">{% for object in related %} - <div class="archive-grid-card archive-grid-card-simple h-entry"> - <a href="{{object.get_absolute_url}}" title="{{object.title}}"> - <div class="card-image-tiny"> - {% if object.featured_image %} - {% include "lib/img_archive.html" with image=object.featured_image nolightbox=True %} - {%endif%} - </div> - <h4 class="p-name card-hed" itemprop="headline">{% if object.title %}{{object.title|safe|smartypants|widont}}{% else %}{{object.common_name}}{%endif%}</h4> - <p class="p-author author hide" ><span class="byline-author">Scott Gilbertson</span></p> - <span class="card-smcaps"> - {% if object.location %}<span class="p-location h-adr adr card-location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place"> - {% if object.location.country_name == "United States" %}{{object.location.state_name}}{%else%}{{object.location.country_name}}{%endif%} - </span>{%endif%} - {% if object.location and object.model_name.model != 'page' %}–{%endif%} - {% if object.model_name.model != 'page' %}<time class="dt-published published dt-updated" datetime="{{object.pub_date|date:'c'}}"><span>{{object.pub_date|date:" Y"}}</span></time>{%endif%} - </span> - </a> - </div> - {% endfor %}</div> - </div> - </div>{%endif%} - <aside class="narrow join mailing-list--wrapper"> - <h6 class="hedtinycaps">If you enjoyed this, you might like <em><a href="/range/">Range</a></em>, A photography (sometimes) newsletter</h6> - <iframe target='_parent' style="border:none !important; background:white; width:100% !important;" title="embedded form for subscribing the the Range newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe> - </aside> - {% if object.enable_comments %} -{% get_comment_count for object as comment_count %} -{%if comment_count > 0 %} -<div class="comment-wrapper"> -<p class="comments-header">{{comment_count}} Comment{{ comment_count|pluralize }}</p> -{% render_comment_list for object %} -{%endif%} -<div class="comment-form-wrapper {%if comment_count > 0%}comment-form-border{%endif%}"> -{% render_comment_form for object %} -</div> -{% else %} -<p class="comments--header" style="text-align: center">Sorry, comments have been disabled for this post.</p> -{%endif%} -</div> </main> {% endblock %} {% block js %} diff --git a/app/posts/templates/posts/guide_post_detail.html b/app/posts/templates/posts/guide_post_detail.html new file mode 100644 index 0000000..42d06a2 --- /dev/null +++ b/app/posts/templates/posts/guide_post_detail.html @@ -0,0 +1,115 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% load comments %} +{%block htmlclass%}class="detail single"{%endblock%} +{% block pagetitle %}{{object.title|title|smartypants|safe}} - by Scott Gilbertson{% endblock %} + +{% block metadescription %}{% autoescape on %}{{object.meta_description|striptags|safe}}{% endautoescape %}{% endblock %}{%block extrahead%} + <link rel="canonical" href="https://luxagraf.net{{object.get_absolute_url}}" /> +{% if object.has_code %} <link rel="stylesheet" href="/media/src/solarized.css" type="text/css" media="screen"/>{%endif %} +{%endblock%} +{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %} +{% block primary %}<main> + <article class="h-entry hentry entry-content content" itemscope itemType="http://schema.org/BlogPosting"> + <header id="header" class="post-header"> + <h1 class="p-name post-title" itemprop="headline">{{object.title|smartypants|safe}}</h1> + {% if object.subtitle %}<h2 class="post-subtitle">{{object.subtitle|smartypants|safe}}</h2>{%endif%} + <div class="post-dateline"> + {% if object.originally_published_by %}<h4 class="post-source">Originally Published By: <a href="{{object.originally_published_by_url}}" title="View {{object.title}} on {{object.originally_published_by}}">{{object.originally_published_by}}</a></h4>{%endif%} + {% if object.location %}<div class="p-location h-adr adr post-location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place"> + <span class="h-adr" itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">{% if object.location.country_name == "United States" %} + <span class="p-locality locality" itemprop="addressLocality">{{object.location.name|smartypants|safe}}</span>, <span class="p-region region">{{object.location.state_name|safe}}</span><span class="p-country-name" itemprop="addressCountry"></span>{%else%} + <span class="p-region" itemprop="addressRegion">{{object.location.name|smartypants|safe}}</span>, <span class="p-country-name country-name"><span itemprop="addressCountry">{{object.location.country_name|safe}}</span></span>{%endif%} + </span> + </div>{%endif%} + <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time> + <span class="hide" itemprop="author" itemscope itemtype="http://schema.org/Person">by <a class="p-author h-card" href="/about"><span itemprop="name">Scott Gilbertson</span></a></span> + </div> + </header> + <div class="e-content entry-content post-body" itemprop="articleBody"> + {% if object.prologue_html %}<div class="post-afterward "> + {{object.prologue_html|smartypants|safe}} + </div><hr />{%endif%} + {{object.body_html|safe|smartypants}} + {% if object.epilogue_html %}<div class="post-afterward"> + {{object.epilogue_html|smartypants|safe}} + </div>{%endif%} + </div> + {%if wildlife or object.field_notes.all or object.books.all %}<div class="entry-footer">{%if wildlife %} + <aside id="wildlife"> + <h3>Fauna and Flora</h3> + {% regroup wildlife by ap.apclass.get_kind_display as wildlife_list %} + <ul> + {% for object_list in wildlife_list %} + <li class="grouper">{{object_list.grouper}}<ul> + {% for object in object_list.list %} + <li>{%if object.ap.body_markdown%}<a href="{% url 'sightings:detail' object.ap.slug %}">{{object}}</a>{%else%}{{object}}{%endif%} </li> + {% endfor %}</ul> + {% endfor %}</ul> + </aside> + {% endif %}{%if object.field_notes.all %} + <aside {% if wildlife %}class="margin-left-none" {%endif%}id="field_notes"> + <h3>Field Notes</h3> + <ul>{% for obj in object.field_notes.all %} + <li><a href="{% url 'fieldnotes:detail' year=obj.pub_date.year month=obj.pub_date|date:"m" slug=obj.slug %}">{{obj}}</a></li> + {% endfor %}</ul> + </aside>{% endif %} + {%if object.books.all %} + <aside id="recommended-reading" {%if object.field_notes.all and wildlife %}class="rr-clear{%endif%}" > + <h3>Recommended Reading</h3> + <ul>{% for obj in object.books.all %} + <li><a href="{% url 'books:detail' slug=obj.slug %}"><img src="{{obj.get_small_image_url}}" /></a></li> + {% endfor %}</ul> + </aside>{% endif %} + </div>{%endif%} + </article> + </main> + {% if object.related.all %}<div class="article-afterward related"> + <div class="related-bottom"> + <h6 class="hedtinycaps">You might also enjoy</h6> + <div class="archive-grid-quad">{% for object in related %} + <div class="archive-grid-card archive-grid-card-simple" itemscope itemtype="https://schema.org/Article"> + <a href="{{object.get_absolute_url}}" title="{{object.title}}"> + <div class="card-image-tiny"> + {% if object.featured_image %} + {% include "lib/img_archive.html" with image=object.featured_image nolightbox=True %} + {%endif%} + </div> + <h4 class="p-name card-hed" itemprop="headline">{% if object.title %}{{object.title|safe|smartypants|widont}}{% else %}{{object.common_name}}{%endif%}</h4> + <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="https://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p> + <span class="card-smcaps"> + {% if object.location %}<span class="p-location h-adr adr card-location" itemprop="contentLocation" itemscope itemtype="https://schema.org/Place"> + {% if object.location.country_name == "United States" %}{{object.location.state_name}}{%else%}{{object.location.country_name}}{%endif%} + </span>{%endif%} + {% if object.location and object.model_name.model != 'page' %}–{%endif%} + {% if object.model_name.model != 'page' %}<time class="dt-published published dt-updated" datetime="{{object.pub_date|date:'c'}}"><span>{{object.pub_date|date:" Y"}}</span></time>{%endif%} + </span> + </a> + </div> + {% endfor %}</div> + </div> + </div>{%endif%} + {% comment %} <div class="mailing-list--wrapper"> + <h5>If you enjoyed this, you should join the mailing list…</h5> + {% include 'mailing_list.html' %} + </div> {% endcomment %} + {% if object.enable_comments %} +{% get_comment_count for object as comment_count %} +{%if comment_count > 0 %} +<div class="comment-wrapper"> +<p class="comments-header">{{comment_count}} Comment{{ comment_count|pluralize }}</p> +{% render_comment_list for object %} +{%endif%} +<div class="comment-form-wrapper {%if comment_count > 0%}comment-form-border{%endif%}"> +{% render_comment_form for object %} +</div> +{% else %} +<p class="comments--header" style="text-align: center">Sorry, comments have been disabled for this post.</p> +</div> +{%endif%} +</div> +{% endblock %} +{% block js %} +<script src="/media/js/detail.min.js"></script> +{{ block.super }} +{%endblock%} diff --git a/app/posts/templates/posts/jrnl_list.html b/app/posts/templates/posts/jrnl_list.html index 6b4411f..a5e9163 100644 --- a/app/posts/templates/posts/jrnl_list.html +++ b/app/posts/templates/posts/jrnl_list.html @@ -5,8 +5,20 @@ {% block metadescription %}{% if region %}Travel writing, essays and dispatches from {{region.name|title|smartypants|safe}}{%else%}Travel writing, essays and dispatches from around the world{%endif%} Page {{page}}{% endblock %} {%block bodyid%}id="writing" class="archive"{%endblock%} {% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %} -{% block primary %}<main class="archive-grid"> - <h1 class="hide">{% if region %}Journal entries from {%if region.name == 'United States'%}the United States{%else%}{{region.name|title|smartypants|safe}}{%endif%}{%else%}Journal {%endif%}</h1>{% autopaginate object_list 24 %} {% for object in object_list %} +{% block primary %}<main role="main" class="archive-wrapper"> + <div class="archive-intro"> + <h1 class="list-hed"><em>Psst</em>, Wanna Join the <em>Friends of a Long Year</em>?</h1> + <iframe target='_parent' style="border:none; background:white; width:100%;" title="embedded form for subscribing the the Friends of a Long Year newsletter" src="{% url 'lttr:subscribe' slug='friends' %}"></iframe> + <h2 class="list-subhed">Say what? </h2> + <p><em>Friends of a Long Year</em> is a private mailing list bringing stories to your inbox like it's still 1995. It's written in the spirit of Mary Austin. It was originally called <em>Place Without a Postcard</em>, which does a better job of summarizing what I like to write about. <em>Friends</em> is delivered roughly twice a month.</p> + <!--<p>If you really want to go nuts and experience the world of like, <a href="https://luxagraf.net/jrnl/2023/08/everyday-1984">1984</a>, you can <a href="/cards">sign up here to get a postcard</a> from us on the road. Yes. Seriously.</p> --> + </div> + <h1 class="archive-sans">Archive</h1>{% autopaginate object_list 24 %} + <nav aria-label="page navigation" class="pagination"> + {% paginate %} + </nav> +<div class="archive-grid"> + {% for object in object_list %} <article class="h-entry hentry archive-grid-card" itemscope itemType="http://schema.org/Article"> <div class="card-image"> <a href="{{object.get_absolute_url}}" title="{{object.title}}">{% if object.featured_image %} @@ -26,6 +38,7 @@ </span> </p> </article> {% endfor %} + </div> </main> <nav aria-label="page navigation" class="pagination"> {% paginate %} diff --git a/app/posts/templates/posts/range_detail.html b/app/posts/templates/posts/range_detail.html index 17c1486..40d8011 100644 --- a/app/posts/templates/posts/range_detail.html +++ b/app/posts/templates/posts/range_detail.html @@ -129,7 +129,7 @@ </div>{%endif%} </nav>{%endwith%}{%endwith%} <aside class="narrow donate join"> - <p>You're reading <em>Range</em>, a weekly mailing of a single photograph, along with a few notes, and video of the processing. If you'd like to join us, drop your email in the form below: </p> + <p>You're reading <em>Range</em>, a weekly mailing about stuff. If you'd like to join us, drop your email in the form below: </p> <iframe style="border:none !important; background:white; width:100% !important;" title="embedded form for subscribing to the Range newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe> </aside> {% if object.related.all %}<div class="article-afterward related"> diff --git a/app/posts/templates/posts/range_list.html b/app/posts/templates/posts/range_list.html index 43275c6..09ad56d 100644 --- a/app/posts/templates/posts/range_list.html +++ b/app/posts/templates/posts/range_list.html @@ -3,38 +3,24 @@ {% block pagetitle %}Luxagraf | Range {% endblock %} {% block metadescription %}An weekly mailing list about living outdoors, photography, literature, music, vintage vehicles, and other ephemera.{% endblock %} {% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %} -{% block primary %} -<main class="archive-wrapper">{% for object in object_list %}{% if forloop.first %} - <figure class="large-top-image"> - <a href="{{object.get_absolute_url}}" title="{{object.title}}">{%with image=object.featured_image%} - <img style="margin:0;" sizes="(max-width: 960px) 100vw" - srcset="{{image.get_srcset}}" - src="{{image.get_src}}" - alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}"> - </a>{%endwith%}{%endif%}{%endfor%} - </figure> +{% block primary %}<main role="main" id="essay-archive" class="essay-archive archive-list"> <div class="archive-intro"> - <h1 class="list-hed">Range</h1> + <h1 class="list-hed">Subscribe to <em>Range</em></h1> + <iframe target='_parent' style="border:none; background:white; width:100%;" title="embedded form for subscribing the the Friends of a Long Year newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe> <h2 class="list-subhed">A weekly post, ranging.</h2> - <p>Please join us by dropping your email in the form below: </p> - <iframe style="border:none !important; background:white; width:100% !important;" title="embedded form for subscribing to the Range newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe> - <p><em>Range</em> is a weekly mailing of photographs and words. </p> - <p>I like to write about things tangential to living on the road, but didn't want to clutter up the Journal with extraneous stuff. I had this newsletter originally as a photo newsletter, but I wanted to let myself, ahem, range a little more than that. You can browse the archives below to see if it interests you, and sign up if it does.</p> - <p>Unsubscribing is easy. It's <a href="/src/building-your-own-mailing-list-software">self-hosted</a> and <a href="/privacy" title="My privacy policy">respects your privacy</a>. If you don't want an email, there's also <a href="/range/feed.xml">an RSS feed</a>, and it's all archived below.</p> - <p>There's also the <em><a href="/friends/">Friends of a Long Year</a></em> newsletter if you want some stories about life on the road in your inbox. You can also <a href="/cards">sign up to get a postcard</a> from us on the road</p> + <p><em>Range</em> is a weekly mailing about life and how to live it. We talk about the intersection of <a href="/essays/">Spirit</a>, <a href="/how-to/">Craft</a>, and <a href="/reviews/">Tools</a>. Browse the archive below. If you like what you see, join us.</p> + <h3><i>Être fort pour être utile</i></h3> </div> - <h3 class="archive-sans">Ranges</h3> - <div class="archive-grid">{% for object in object_list %} - <article class="h-entry hentry archive-grid-card" itemscope itemType="http://schema.org/Article"> - <div class="card-image"> - <a href="{{object.get_absolute_url}}" title="{{object.title}}"> - {% include "lib/img_archive.html" with image=object.featured_image %} + <h3 class="archive-sans archive-hed">Archive</h3> + <div class="archive-list">{% for object in object_list %} + <article class="h-entry hentry archive-list-card archive-list-card-sm" itemscope itemType="http://schema.org/Article"> + <time class="date dt-published card-smcaps">{{object.pub_date|date:"F Y"}}</time> + <a href="{{object.get_absolute_url}}"> + <h2 class="card-hed">{{object.title|safe|smartypants|widont}}</h2> + <h3 class="p-summary card-lede">{% if object.subtitle %}{{object.subtitle|safe|smartypants|widont}}{%endif%}</h3> </a> - </div> - <h2 class="p-name card-hed-it" itemprop="headline"><a href="{{object.get_absolute_url}}" class="u-url" title="{{object.title}}">{{object.title|safe|smartypants|widont}}</a></h2> - <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p> - <time class="dt-published published dt-updated card-smcaps" datetime="{{object.pub_date|date:'c'}}">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time> - </article> {% endfor %} + <span style="display: block" class="card-smcaps">Filed Under: {{object.get_post_topic_display}}{% for obj in object.topics.all %}{%if forloop.last or forloop.first %}, {%endif%}{{obj}}{%endfor%}</span> + </article>{%endfor%} </div> </main> {%endblock%} diff --git a/app/posts/templates/posts/range_listold.html b/app/posts/templates/posts/range_listold.html new file mode 100644 index 0000000..43275c6 --- /dev/null +++ b/app/posts/templates/posts/range_listold.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% block pagetitle %}Luxagraf | Range {% endblock %} +{% block metadescription %}An weekly mailing list about living outdoors, photography, literature, music, vintage vehicles, and other ephemera.{% endblock %} +{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %} +{% block primary %} +<main class="archive-wrapper">{% for object in object_list %}{% if forloop.first %} + <figure class="large-top-image"> + <a href="{{object.get_absolute_url}}" title="{{object.title}}">{%with image=object.featured_image%} + <img style="margin:0;" sizes="(max-width: 960px) 100vw" + srcset="{{image.get_srcset}}" + src="{{image.get_src}}" + alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}"> + </a>{%endwith%}{%endif%}{%endfor%} + </figure> + <div class="archive-intro"> + <h1 class="list-hed">Range</h1> + <h2 class="list-subhed">A weekly post, ranging.</h2> + <p>Please join us by dropping your email in the form below: </p> + <iframe style="border:none !important; background:white; width:100% !important;" title="embedded form for subscribing to the Range newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe> + <p><em>Range</em> is a weekly mailing of photographs and words. </p> + <p>I like to write about things tangential to living on the road, but didn't want to clutter up the Journal with extraneous stuff. I had this newsletter originally as a photo newsletter, but I wanted to let myself, ahem, range a little more than that. You can browse the archives below to see if it interests you, and sign up if it does.</p> + <p>Unsubscribing is easy. It's <a href="/src/building-your-own-mailing-list-software">self-hosted</a> and <a href="/privacy" title="My privacy policy">respects your privacy</a>. If you don't want an email, there's also <a href="/range/feed.xml">an RSS feed</a>, and it's all archived below.</p> + <p>There's also the <em><a href="/friends/">Friends of a Long Year</a></em> newsletter if you want some stories about life on the road in your inbox. You can also <a href="/cards">sign up to get a postcard</a> from us on the road</p> + </div> + <h3 class="archive-sans">Ranges</h3> + <div class="archive-grid">{% for object in object_list %} + <article class="h-entry hentry archive-grid-card" itemscope itemType="http://schema.org/Article"> + <div class="card-image"> + <a href="{{object.get_absolute_url}}" title="{{object.title}}"> + {% include "lib/img_archive.html" with image=object.featured_image %} + </a> + </div> + <h2 class="p-name card-hed-it" itemprop="headline"><a href="{{object.get_absolute_url}}" class="u-url" title="{{object.title}}">{{object.title|safe|smartypants|widont}}</a></h2> + <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p> + <time class="dt-published published dt-updated card-smcaps" datetime="{{object.pub_date|date:'c'}}">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time> + </article> {% endfor %} + </div> + </main> +{%endblock%} + + <p>If you're not familiar, darktable is open source raw image developer. It's free, you can download a copy for Linux, macOS, or Windows. The <a href="https://www.darktable.org/usermanual/en/">darktable user manual</a> is very helpful if you're brand new. I also recommend <a href="https://www.youtube.com/user/audio2u">Bruce Williams' darktable videos</a>, and <a href="https://www.youtube.com/user/s7habo/videos">Boris Hajdukovic's videos</a>, which were the inspiration for what you see here.</p> + <p>I'm no expert either, so feel free to hit reply and let me know if I get something wrong.</p> diff --git a/app/posts/templates/posts/review_list.html b/app/posts/templates/posts/review_list.html new file mode 100644 index 0000000..5dcaa72 --- /dev/null +++ b/app/posts/templates/posts/review_list.html @@ -0,0 +1,21 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% block pagetitle %}Notes and Essays On Living - By Scott Gilbertson {% endblock %} +{% block metadescription %}Essays and stories on self-reliance, DIY, repair, tools, birding, walking, living well, and other ephemera.{% endblock %} +{% block breadcrumbs %}{% if breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{%endif%}{% endblock %} +{% block primary %}<main role="main" id="essay-archive" class="essay-archive archive-list"> + <div class="archive-intro"> + <h1>Tools</h1> + <h3>At some point the wrench must be turned, the shutter clicked, the paper scratched. The right tool makes all the difference. In decades of testing, these are the best I've used.</h3> + </div> + <ul class="archive-list">{% for object in object_list %} + <li class="h-entry hentry archive-list-card archive-list-card-sm" itemscope itemType="http://schema.org/Article"> + <span class="date dt-published card-smcaps">{{object.pub_date|date:"F Y"}}</span> + <a href="{{object.get_absolute_url}}"> + <h2 class="card-hed">{{object.title|safe|smartypants|widont}}</h2> + <p class="p-summary card-lede">{% if object.subtitle %}{{object.subtitle}}{%else%}{{object.meta_description|safe|smartypants|widont}}{%endif%}</p> + </a> + </li>{%endfor%} + </ul> + </main> +{%endblock%} diff --git a/app/posts/urls/guide_urls.py b/app/posts/urls/guide_urls.py index f3891e3..5e2b37e 100644 --- a/app/posts/urls/guide_urls.py +++ b/app/posts/urls/guide_urls.py @@ -10,16 +10,20 @@ urlpatterns = [ r'', views.GuideListView.as_view(), {'page':1}, - name="guide-base" + name="guide-list" ), path( - r'<str:topic>/', - views.GuideTopicListView.as_view(), - {'page':1}, - name="guides-by-topic" + r'<int:page>/', + views.GuideListView.as_view(), + name="guide-list" ), path( r'<str:topic>/<str:slug>', + views.GuidePostDetailView.as_view(), + name="guide-post-detail" + ), + path( + r'<str:slug>/', views.GuideDetailView.as_view(), name="guide-detail" ), diff --git a/app/posts/urls/range_urls.py b/app/posts/urls/range_urls.py index 16655d6..e035a25 100644 --- a/app/posts/urls/range_urls.py +++ b/app/posts/urls/range_urls.py @@ -12,14 +12,14 @@ urlpatterns = [ name="feed" ), path( - r'<int:issue>/<str:slug>', - views.RangeDetailView.as_view(), - name="range-detail" - ), - path( r'', views.RangeListView.as_view(), {'page':1}, name="range-list" ), + path( + r'<int:page>', + views.RangeListView.as_view(), + name="range-list" + ), ] diff --git a/app/posts/urls/review_urls.py b/app/posts/urls/review_urls.py index 6b78e43..3c8368d 100644 --- a/app/posts/urls/review_urls.py +++ b/app/posts/urls/review_urls.py @@ -1,28 +1,28 @@ from django.urls import path, re_path -from ..views import guide_views as views +from ..views import review_views as views app_name = "reviews" urlpatterns = [ path( r'<str:slug>', - views.PostDetailView.as_view(), + views.ReviewDetailView.as_view(), name="review-detail" ), path( r'<str:slug>.txt', - views.PostDetailViewTXT.as_view(), + views.ReviewDetailViewTXT.as_view(), name="review-detail-txt" ), path( r'<int:page>/', - views.ReviewsListView.as_view(), + views.ReviewListView.as_view(), name="review-list" ), path( r'', - views.ReviewsListView.as_view(), + views.ReviewListView.as_view(), {'page':1}, name="review-list" ), diff --git a/app/posts/views/essay_views.py b/app/posts/views/essay_views.py index ca1697f..02a1087 100644 --- a/app/posts/views/essay_views.py +++ b/app/posts/views/essay_views.py @@ -1,6 +1,7 @@ from django.views.generic import ListView from django.views.generic.detail import DetailView from django.contrib.syndication.views import Feed +from django.urls import reverse from django.apps import apps from django.conf import settings @@ -43,6 +44,8 @@ class EssayDetailView(LuxDetailView): model = apps.get_model(obj.model_name.app_label, obj.model_name.model) related.append(model.objects.get(slug=obj.slug, pub_date=obj.pub_date)) context['related'] = related + context['breadcrumbs'] = ('Range',) + context['crumb_url'] = reverse('range:range-list') return context def get_template_names(self): diff --git a/app/posts/views/film_views.py b/app/posts/views/film_views.py index 3122240..48bdaa4 100644 --- a/app/posts/views/film_views.py +++ b/app/posts/views/film_views.py @@ -1,6 +1,7 @@ from django.views.generic import ListView from django.views.generic.detail import DetailView from django.contrib.syndication.views import Feed +from django.urls import reverse from django.apps import apps from django.conf import settings @@ -43,6 +44,8 @@ class FilmDetailView(LuxDetailView): model = apps.get_model(obj.model_name.app_label, obj.model_name.model) related.append(model.objects.get(slug=obj.slug, pub_date=obj.pub_date)) context['related'] = related + context['breadcrumbs'] = ('Range',) + context['crumb_url'] = reverse('range:range-list') return context def get_template_names(self): diff --git a/app/posts/views/guide_views.py b/app/posts/views/guide_views.py index 641da66..e19a7db 100644 --- a/app/posts/views/guide_views.py +++ b/app/posts/views/guide_views.py @@ -7,7 +7,7 @@ from django.conf import settings from utils.views import PaginatedListView, LuxDetailView -from ..models import Post, PostType +from ..models import Guide, Post, PostType from taxonomy.models import Category @@ -15,44 +15,18 @@ class GuideListView(PaginatedListView): """ Return a list of Entries in reverse chronological order """ - model = Post + model = Guide template_name = "posts/guide_base.html" def get_queryset(self): queryset = super(GuideListView, self).get_queryset() - return queryset.filter(status__exact=1).filter(post_type__in=[PostType.REVIEW,PostType.GUIDE]).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') - - -class GuideTopicListView(PaginatedListView): - """ - Return a list of Posts by topic in reverse chronological order - """ - model = Post - template_name = "posts/guide_by_topic.html" - - def get_queryset(self): - queryset = super(GuideTopicListView, self).get_queryset() - topic = Category.objects.get(slug=self.kwargs['topic']) - return queryset.filter(status__exact=1).filter(topics__slug=topic.slug).order_by('-pub_date').prefetch_related('featured_image') - - def get_context_data(self, **kwargs): - context = super(GuideTopicListView, self).get_context_data(**kwargs) - topic = Category.objects.get(slug=self.kwargs['topic']) - context['topic'] = topic - context['breadcrumbs'] = ('Guides', topic.name ) - context['crumb_url'] = reverse('guides:guide-base') - - Category.objects.get(slug=self.kwargs['topic']) - return context + return queryset.filter(status__exact=1) class GuideDetailView(LuxDetailView): - model = Post + model = Guide slug_field = "slug" - def get_template_names(self): - obj = self.get_object() - return ["posts/%s_detail.html" % obj.get_post_type_display(), 'posts/post_detail.html'] def get_context_data(self, **kwargs): context = super(GuideDetailView, self).get_context_data(**kwargs) @@ -61,8 +35,14 @@ class GuideDetailView(LuxDetailView): model = apps.get_model(obj.model_name.app_label, obj.model_name.model) related.append(model.objects.get(slug=obj.slug, pub_date=obj.pub_date)) context['related'] = related - topic = Category.objects.get(slug=self.kwargs['topic']) - context['topic'] = topic - context['breadcrumbs'] = ('Guides', topic.name ) - context['crumb_url'] = reverse('guides:guide-base') + context['breadcrumbs'] = ('Guides', self.object.title ) + context['crumb_url'] = reverse('guides:guide-list') return context + + +class GuidePostDetailView(LuxDetailView): + model = Post + slug_field = "slug" + template_name = "posts/guide_post_detail.html" + + diff --git a/app/posts/views/range_views.py b/app/posts/views/range_views.py index da3b61f..f196e5e 100644 --- a/app/posts/views/range_views.py +++ b/app/posts/views/range_views.py @@ -18,29 +18,13 @@ from locations.models import LuxCheckIn, Country, Region, Location from sightings.models import Sighting -class RangeDetailView(LuxDetailView): - model = Post - slug_field = "slug" - template_name = "posts/range_detail.html" - - def get_context_data(self, **kwargs): - context = super(RangeDetailView, self).get_context_data(**kwargs) - related = [] - for obj in self.object.related.all(): - model = apps.get_model(obj.model_name.app_label, obj.model_name.model) - related.append(model.objects.get(slug=obj.slug, pub_date=obj.pub_date)) - context['related'] = related - context['mailing'] = NewsletterMailing.objects.get(post__id=self.object.id) - return context - - class RangeListView(PaginatedListView): """ Return a list of Newsletter posts in reverse chronological order """ model = Post template_name = "posts/range_list.html" - queryset = Post.objects.filter(post_type=PostType.RANGE,status=1).order_by('-pub_date') + queryset = Post.objects.filter(post_type__in=[PostType.ESSAY,PostType.FILM,PostType.HOWTO,PostType.REVIEW],status=1).order_by('-pub_date') def get_context_data(self, **kwargs): context = super(RangeListView, self).get_context_data(**kwargs) diff --git a/app/posts/views/repair_views.py b/app/posts/views/repair_views.py new file mode 100644 index 0000000..0a5eabf --- /dev/null +++ b/app/posts/views/repair_views.py @@ -0,0 +1,53 @@ +from django.views.generic import ListView +from django.views.generic.detail import DetailView +from django.views.generic.dates import DateDetailView +from django.urls import reverse +from django.views.generic.dates import YearArchiveView, MonthArchiveView +from django.contrib.syndication.views import Feed +from django.apps import apps +from django.shortcuts import get_object_or_404 +from django.conf import settings +from django.db.models import Q + +from utils.views import PaginatedListView, LuxDetailView + +#from ..models import Entry, HomepageCurrator, Home +from ..models import Post, PostType +from locations.models import LuxCheckIn, Country, Region, Location +from sightings.models import Sighting + + +class RepairStoryDetailView(LuxDetailView): + model = Post + slug_field = "slug" + template_name = "posts/repair_detail.html" + + +class RepairStoryListView(PaginatedListView): + """ + Return a list of Newsletter posts in reverse chronological order + """ + model = Post + template_name = "posts/repair_list.html" + + def get_context_data(self, **kwargs): + context = super(FriendsListView, self).get_context_data(**kwargs) + context['breadcrumbs'] = ['repair',] + return context + + +class FriendsRSSFeedView(Feed): + title = "Friends of a Long Year" + link = "/range/" + description = "Friends of a Long Year: A monthly newsletter" + description_template = 'feeds/blog_description.html' + + def items(self): + return Post.objects.filter(status__exact=1).filter(post_type=PostType.FRIENDS).order_by('-pub_date')[:10] + + def item_pubdate(self, item): + """ + Takes an item, as returned by items(), and returns the item's + pubdate. + """ + return item.pub_date diff --git a/app/posts/views/review_views.py b/app/posts/views/review_views.py new file mode 100644 index 0000000..353a5e9 --- /dev/null +++ b/app/posts/views/review_views.py @@ -0,0 +1,53 @@ +from django.views.generic import ListView +from django.views.generic.detail import DetailView +from django.contrib.syndication.views import Feed +from django.urls import reverse +from django.apps import apps +from django.conf import settings + +from utils.views import PaginatedListView, LuxDetailView + +from ..models import Post, PostType +from taxonomy.models import Category + + +class ReviewListView(PaginatedListView): + model = Post + template_name = "posts/review_list.html" + + def get_queryset(self): + queryset = super(ReviewListView, self).get_queryset() + return queryset.filter(site__domain='luxagraf.net').filter(post_type__in=[PostType.REVIEW]).filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') + + def get_context_data(self, **kwargs): + ''' + override for custom breadcrumb path + ''' + # Call the base implementation first to get a context + context = super(ReviewListView, self).get_context_data(**kwargs) + context['breadcrumbs'] = ('Reviews',) + return context + + +class ReviewDetailView(LuxDetailView): + model = Post + slug_field = "slug" + + def get_context_data(self, **kwargs): + context = super(ReviewDetailView, self).get_context_data(**kwargs) + related = [] + for obj in self.object.related.all(): + model = apps.get_model(obj.model_name.app_label, obj.model_name.model) + related.append(model.objects.get(slug=obj.slug, pub_date=obj.pub_date)) + context['related'] = related + context['breadcrumbs'] = ('Range',) + context['crumb_url'] = reverse('range:range-list') + return context + + def get_template_names(self): + obj = self.get_object() + return ["posts/review_detail.html"] + + +class ReviewDetailViewTXT(ReviewDetailView): + template_name = "posts/entry_detail.txt" |