Changeset - 75e3ab4d35f0
[Not reviewed]
0 8 0
Ben Sturmfels (bsturmfels) - 3 months ago 2024-02-23 04:02:04
ben@sturm.com.au
podjango: Fix linting warnings
8 files changed with 84 insertions and 64 deletions:
0 comments (0 inline, 0 general)
TODO.md
Show inline comments
 
# To-do
 

	
 
* remove `ForceCanonicalHostnameMiddleware` by ensuring canonical redirect and HTTPS redirect is done by Apache
 
* serve a 400 in Apache for a hostname we don't explicitly support
 
* use `<detail>` elements for supporter page hidden sections, rather than complex jQuery - or consider Alpine.js
 
* replace `internalNavigate` with inline flexbox layout
 
* migrate to Django 4.2
 
* add deployment script that runs migrations and collects static files
 
* add tests for main pages returning 200
 
* switch to `path` in URLconfs
 
* review `apache2` directory - may be unused
 
* standardise settings to replace `settings.py` and `djangocommonsettings.py`
 
  with `settings/prod.py` and move `SECRET_KEY` to an environment variable
 

	
 

	
 
# Done
conservancy/podjango/admin.py
Show inline comments
...
 
@@ -15,24 +15,26 @@
 
# You should have received a copy of the GNU Affero General Public License
 
# along with this program in a file in the toplevel directory called
 
# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
 
#
 
from django.contrib import admin
 

	
 
from .models import Cast, CastTag
 

	
 

	
 
class CastTagAdmin(admin.ModelAdmin):
 
    prepopulated_fields = {'slug': ('label',)}
 

	
 

	
 
admin.site.register(CastTag, CastTagAdmin)
 

	
 

	
 
class CastAdmin(admin.ModelAdmin):
 
    list_display = ('pub_date', 'title')
 
    list_filter = ['pub_date']
 
    date_hierarchy = 'pub_date'
 
    search_fields = ['title', 'summary', 'body']
 
    prepopulated_fields = {'slug': ("title",)}
 
    filter_horizontal = ('tags',)
 

	
 

	
 
admin.site.register(Cast, CastAdmin)
conservancy/podjango/feeds.py
Show inline comments
...
 
@@ -9,28 +9,25 @@
 
#
 
# This program is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
 
# General Public License for more details.
 
#
 
# You should have received a copy of the GNU Affero General Public License
 
# along with this program in a file in the toplevel directory called
 
# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 
from datetime import datetime
 
import itertools
 
import operator
 

	
 
from django.conf import settings
 
from django.contrib.sites.shortcuts import get_current_site
 
from django.contrib.syndication.views import Feed, add_domain
 
from django.shortcuts import render
 
from django.utils.feedgenerator import Rss201rev2Feed
 

	
 
from .models import Cast
 

	
 
# FIXME: Settings here should not be hard-coded for given casts, but
 
# should instead have settings from the main screen.
 

	
 
class CastFeedBase(Feed):
 
    def copyright_holder(self): return "Bradley M. Kuhn, Karen M. Sandler"
...
 
@@ -44,121 +41,129 @@ class CastFeedBase(Feed):
 
                if hasattr(getattr(item, attr), 'year'):
 
                    year = getattr(getattr(item, attr), 'year')
 
                    break
 
        return 'Copyright (C) %d, %s.  %s' % (year, self.copyright_holder(), self.license_no_html())
 

	
 
    def item_extra_kwargs(self, item):
 
        year = 2008
 
        for attr in ('pub_date', 'date_created', 'date_last_modified'):
 
            if hasattr(item, attr):
 
                if hasattr(getattr(item, attr), 'year'):
 
                    year = getattr(getattr(item, attr), 'year')
 
                    break
 
        return { 'year' : year }
 
        return {'year': year}
 

	
 

	
 
def for_podcast_feed_extra_kwargs(self, obj):
 
    return { 'managingEditorNames' : 'Bradley and Karen',
 
             'rssImage' : { 'url' : 'http://faif.us/img/cast/faif_144x144.jpg',
 
                            'width' : '144', 'height' : '144' },
 
             'webMaster' : 'oggcast@faif.us (Bradley and Karen)',
 
             'dcCreator' : 'oggcast@faif.us (Bradley and Karen)',
 
             'iTunesExplicit'  : 'No',
 
             'iTunesBlock' : 'No',
 
             'iTunesImage' : { 'url' : 'http://faif.us/img/cast/faif_300x300.jpg',
 
                               'title' : 'The Corresponding Source (formerly Free as in Freedom)',
 
                               'link' : self.author_link,
 
                               'type' : 'video/jpg'},
 
             'category' : { 'name' : 'Government & Organizations', 'scheme' : 'http://www.itunes.com/dtds/podcast-1.0.dtd',
 
                            'subcats' : [ 'Non-Profit' ] },
 
             'keywords' : 'open source, opensource, freesoftware, software freedom, legal, law, linux, free, license, gpl, lgpl, agpl, bsd',
 
             'iTunesAuthor' : 'Software Freedom Conservancy',
 
             'iTunesSubtitle' : 'Bi-Weekly Discussion of Legal, Policy, and Any other Issues in the Free, Libre, and Open Source Software (FLOSS) Community',
 
             'copyrightHolder' : self.copyright_holder(),
 
             'copyrightLicense' : self.license_no_html() }
 
    return {
 
        'managingEditorNames': 'Bradley and Karen',
 
        'rssImage': {'url': 'http://faif.us/img/cast/faif_144x144.jpg',
 
                     'width': '144', 'height': '144'},
 
        'webMaster': 'oggcast@faif.us (Bradley and Karen)',
 
        'dcCreator': 'oggcast@faif.us (Bradley and Karen)',
 
        'iTunesExplicit': 'No',
 
        'iTunesBlock': 'No',
 
        'iTunesImage': {'url': 'http://faif.us/img/cast/faif_300x300.jpg',
 
                        'title': 'The Corresponding Source (formerly Free as in Freedom)',
 
                        'link': self.author_link,
 
                        'type': 'video/jpg'},
 
        'category': {'name': 'Government & Organizations', 'scheme': 'http://www.itunes.com/dtds/podcast-1.0.dtd',
 
                     'subcats': ['Non-Profit']},
 
        'keywords': 'open source, opensource, freesoftware, software freedom, legal, law, linux, free, license, gpl, lgpl, agpl, bsd',
 
        'iTunesAuthor': 'Software Freedom Conservancy',
 
        'iTunesSubtitle': 'Bi-Weekly Discussion of Legal, Policy, and Any other Issues in the Free, Libre, and Open Source Software (FLOSS) Community',
 
        'copyrightHolder': self.copyright_holder(),
 
        'copyrightLicense': self.license_no_html(),
 
    }
 

	
 

	
 
def for_podcast_item_extra_kwargs(self, item):
 
    return { 'duration' : item.duration,
 
             'year' : item.date_created.year,
 
             'dcCreator' : 'oggcast@faif.us (Bradley and Karen)',
 
             'intheitembkuhn' : item.__dict__.__str__()}
 
    return {
 
        'duration': item.duration,
 
        'year': item.date_created.year,
 
        'dcCreator': 'oggcast@faif.us (Bradley and Karen)',
 
        'intheitembkuhn': item.__dict__.__str__(),
 
    }
 

	
 

	
 
def podcast_helper_add_root_elements(self, handler):
 
    handler.addQuickElement('managingEditor', self.feed['author_email'] 
 
    handler.addQuickElement('managingEditor', self.feed['author_email']
 
                            + ' (' + self.feed['managingEditorNames'] + ')')
 
    handler.startElement('image', {})
 
    handler.addQuickElement('url', self.feed['rssImage']['url'])
 
    handler.addQuickElement('title', self.feed['author_name'])
 
    handler.addQuickElement('link', self.feed['link'])
 
    handler.addQuickElement('width', self.feed['rssImage']['width'])
 
    handler.addQuickElement('height', self.feed['rssImage']['height'])
 
    handler.endElement('image')
 
    
 

 
    handler.addQuickElement('webMaster', self.feed['webMaster'])
 
#    handler.addQuickElement('dc:creator', self.feed['dcCreator'])
 
    handler.addQuickElement('itunes:explicit', self.feed['iTunesExplicit'])
 
    handler.addQuickElement('itunes:block', self.feed['iTunesBlock'])
 
    handler.addQuickElement('generator', 'http://www.faif.us/code')
 
    
 

 
    handler.addQuickElement('media:thumbnail', '' , { 'url' : self.feed['rssImage']['url'] })
 
    handler.addQuickElement('itunes:image', '' , { 'href' : self.feed['iTunesImage']['url']})
 
#    handler.addQuickElement('itunes:link', '', { 'href' : self.feed['iTunesImage']['url'],
 
#                                                 'type' : self.feed['iTunesImage']['type']})
 
    
 

 
    handler.addQuickElement("media:category", self.feed['category']['name'],
 
                            { 'scheme': self.feed['category']['scheme']})
 
    if not (self.feed['category']['subcats'] and len(self.feed['category']['subcats']) > 0): 
 
        handler.addQuickElement("itunes:category", '', { 'text': self.feed['category']['name']})
 
                            {'scheme': self.feed['category']['scheme']})
 
    if not (self.feed['category']['subcats'] and len(self.feed['category']['subcats']) > 0):
 
        handler.addQuickElement("itunes:category", '', {'text': self.feed['category']['name']})
 
    else:
 
        handler.startElement("itunes:category", { 'text': self.feed['category']['name']})
 
        handler.startElement("itunes:category", {'text': self.feed['category']['name']})
 
        for cc in self.feed['category']['subcats']:
 
            handler.addQuickElement("itunes:category", '', { 'text': cc })
 
            handler.addQuickElement("itunes:category", '', {'text': cc})
 
        handler.endElement("itunes:category")
 

	
 
    handler.addQuickElement("media:keywords", self.feed['keywords'].replace(" ", ","))
 
    
 

 
    handler.startElement("itunes:owner", {})
 
    handler.addQuickElement("itunes:email", self.feed['author_email'])
 
    handler.addQuickElement("itunes:name", self.feed['author_name'])
 
    handler.endElement("itunes:owner")
 
    
 

 
    handler.addQuickElement("itunes:summary", self.feed['description'])
 
    handler.addQuickElement("itunes:subtitle", self.feed['iTunesSubtitle'])
 
    
 

 
    handler.addQuickElement("itunes:author", self.feed['iTunesAuthor'])
 
    handler.addQuickElement('atom:link', '', { 'rel' : "self",  'href'  : self.feed['feed_url'],
 
                                                'type' : "application/rss+xml"})
 
    
 
    handler.addQuickElement('atom:link', '', {'rel': "self", 'href': self.feed['feed_url'],
 
                                              'type': "application/rss+xml"})
 

	
 
    years = {}
 
    for ii in self.items: years[ii['year']] = 1
 
    
 

 
    copyrightString = ""
 
    ll = years.keys()
 
    sorted(ll)
 
    for yy in ll: copyrightString += "%d, " % yy 
 
    copyrightString += "%s.  %s" % (self.feed['copyrightHolder'], self.feed['copyrightLicense'])
 
    
 

 
    handler.addQuickElement('copyright', copyrightString)
 
    handler.addQuickElement('media:copyright', "Copyright (C) " + copyrightString)
 
    
 

	
 

	
 
def podcast_helper_add_item_elements(self, handler, item):
 
    handler.addQuickElement("itunes:explicit", self.feed['iTunesExplicit'])
 
    handler.addQuickElement("itunes:block", self.feed['iTunesBlock'])
 
    handler.addQuickElement("itunes:keywords", self.feed['keywords'])
 
#    handler.addQuickElement('dc:creator', self.feed['dcCreator'])
 
    handler.addQuickElement("itunes:author", item['author_name'])
 
    handler.addQuickElement("itunes:duration", item['duration'])
 
    if 'enclosure' in item:
 
        handler.addQuickElement('media:content', '', { 'url' : item['enclosure'].url,
 
                                                       'fileSize' : item['enclosure'].length,
 
                                                       'type' : item['enclosure'].mime_type})
 
        handler.addQuickElement('media:content', '', {'url': item['enclosure'].url,
 
                                                      'fileSize': item['enclosure'].length,
 
                                                      'type': item['enclosure'].mime_type})
 

	
 
# http://www.feedforall.com/itune-tutorial-tags.htm
 
# http://www.feedforall.com/mediarss.htm
 
class iTunesFeedType(Rss201rev2Feed):
 
    def root_attributes(self):
 
        attrs = super().root_attributes()
 
        attrs['xmlns:itunes'] = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
 
        attrs['xmlns:atom'] = 'http://www.w3.org/2005/Atom'
 
        attrs['xmlns:media'] = 'http://search.yahoo.com/mrss/'
 
#        attrs['xmlns:dc'] = "http://purl.org/dc/elements/1.1/"
 
        return attrs
 

	
...
 
@@ -201,60 +206,63 @@ class CastFeed(CastFeedBase):
 
        return item.get_absolute_url()
 

	
 
    def item_author_email(self, obj):
 
        return "oggcast@faif.us"
 

	
 
    def item_author_name(self, obj):
 
        return "Software Freedom Conservancy"
 

	
 
    def item_author_link(self, obj):
 
        return "http://faif.us"
 

	
 
    def item_categories(self, item):
 
        return  ('Technology',)
 
        return ('Technology',)
 

	
 
    def copyright_holder(self): return "Software Freedom Conservancy"
 

	
 
    def license_no_html(self): return "Licensed under a Creative Commons Attribution-Share Alike 3.0 USA License."
 

	
 
    def feed_extra_kwargs(self, obj):
 
        return for_podcast_feed_extra_kwargs(self, obj)
 

	
 
    def item_extra_kwargs(self, item):
 
        return for_podcast_item_extra_kwargs(self, item)
 

	
 
# FIXME: 
 
# FIXME:
 
# GUEST NAME GOES HERE!!!
 
#<itunes:author>
 
#     If applicable, at the item level, this tag can contain information
 
#     about the person(s) featured on a specific episode.
 

	
 

	
 
class Mp3CastFeed(CastFeed):
 
    def item_enclosure_mime_type(self): return "audio/mpeg"
 
    def item_enclosure_url(self, item):
 
        return add_domain(self.current_site.domain, item.mp3_path, self.is_secure)
 
    def item_enclosure_length(self, item):
 
        return item.mp3_length
 

	
 

	
 
class OggCastFeed(CastFeed):
 
    def item_enclosure_mime_type(self): return "audio/ogg"
 
    def item_enclosure_url(self, item):
 
        return add_domain(self.current_site.domain, item.ogg_path, self.is_secure)
 
    def item_enclosure_length(self, item):
 
        return item.ogg_length
 

	
 

	
 
feed_dict = {
 
    'cast-ogg': OggCastFeed,
 
    'cast-mp3': Mp3CastFeed,
 
}
 

	
 
# make each feed know its canonical url
 
for k, v in feed_dict.items():
 
    v.get_absolute_url = '/feeds/%s/' % k
 

	
 

	
 
def view(request):
 
    """Listing of all available feeds
 
    """
 

	
 
    feeds = feed_dict.values()
 
    return render(request, "feeds.html", {'feeds': feeds})
conservancy/podjango/frontpage.py
Show inline comments
...
 
@@ -8,25 +8,25 @@
 
# version 3 of the License, or (at your option) any later version of the
 
# AGPL published by the FSF.
 
#
 
# This program is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
 
# General Public License for more details.
 
#
 
# You should have received a copy of the GNU Affero General Public License
 
# along with this program in a file in the toplevel directory called
 
# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
 

	
 
from datetime import datetime, timedelta
 
from datetime import datetime
 

	
 
from django.shortcuts import render
 

	
 
from .models import Cast
 

	
 

	
 
def view(request):
 
    """Cast front page view
 
    Performs all object queries necessary to render the front page.
 
    """
 

	
 
    cast = Cast.objects.all().filter(pub_date__lte=datetime.now())[:3]
conservancy/podjango/models.py
Show inline comments
...
 
@@ -44,28 +44,30 @@ class CastManager(models.Manager):
 
        return super().get_queryset().filter(pub_date__year__gte=2024)
 

	
 

	
 
class Cast(models.Model):
 
    """Cast"""
 

	
 
    title = models.CharField(max_length=200)
 
    slug = models.SlugField(unique=True)
 
    summary = models.TextField(help_text="Use raw HTML.  This summary is not included at the beginning of the body when the entry is displayed.  It used only for the material on the front page.")
 
    body = models.TextField(help_text="Use raw HTML.  Include the full body of any show notes or other information about this episode.  It will be labelled on the site as Show Notes.  It is included on the detail entry, and in the description data on the cast RSS feed.")
 
    pub_date = models.DateTimeField()
 
    tags = models.ManyToManyField(CastTag, blank=True)
 
    ogg_path = models.CharField(max_length=300, blank=True,
 
                             help_text="Local filename of the Ogg file, relative to webroot.  File should be uploaded into the static media area for casts.")
 
    mp3_path = models.CharField(max_length=300, blank=True,
 
                             help_text="Local filename of the mp3 file, relative to webroot.  File should be uploaded into the static media area for casts.")
 
    ogg_path = models.CharField(
 
        max_length=300, blank=True,
 
        help_text="Local filename of the Ogg file, relative to webroot.  File should be uploaded into the static media area for casts.")
 
    mp3_path = models.CharField(
 
        max_length=300, blank=True,
 
        help_text="Local filename of the mp3 file, relative to webroot.  File should be uploaded into the static media area for casts.")
 
    ogg_length = models.IntegerField(blank=False, help_text="size in bytes of ogg file")
 
    mp3_length = models.IntegerField(blank=False, help_text="size in bytes of mp3 file")
 
    duration = models.CharField(max_length=8, blank=False, help_text="length in hh:mm:ss of mp3 file")
 
    date_created = models.DateTimeField(auto_now_add=True)
 
    date_last_modified = models.DateTimeField(auto_now=True)
 

	
 
    objects = CastManager()
 

	
 
    class Meta:
 
        db_table = 'casts_entries'  # legacy
 
        verbose_name_plural = 'casts'
 
        ordering = ('-pub_date',)
conservancy/podjango/templatetags/date_within.py
Show inline comments
 
from datetime import datetime, timedelta
 

	
 
from django import template
 

	
 
register = template.Library()
 

	
 

	
 
@register.filter
 
def date_within_past_days(value, arg):
 
    # question: does datetime.now() do a syscall each time is it called?
 
    return value > (datetime.now() - timedelta(days=int(arg)))
conservancy/podjango/urls.py
Show inline comments
...
 
@@ -8,37 +8,37 @@
 
# version 3 of the License, or (at your option) any later version of the
 
# AGPL published by the FSF.
 
#
 
# This program is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
 
# General Public License for more details.
 
#
 
# You should have received a copy of the GNU Affero General Public License
 
# along with this program in a file in the toplevel directory called
 
# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import datetime
 

	
 
from django.conf import settings
 
from django.conf.urls import include, url
 
from django.contrib import admin
 
from django.contrib.syndication.views import Feed
 
from django.conf.urls import url
 
from django.views.generic.dates import (
 
    DateDetailView,
 
    DayArchiveView,
 
    MonthArchiveView,
 
    YearArchiveView,
 
)
 

	
 
from . import frontpage
 
from .feeds import Mp3CastFeed, OggCastFeed, feed_dict, view
 
from .feeds import Mp3CastFeed, OggCastFeed, view
 
from .models import Cast, CastTag
 
from .views import custom_index, query
 

	
 
app_name = 'podjango'
 

	
 
extra_context = {}
 
info_dict = {
 
    'queryset': Cast.objects.all(),
 
    'date_field': 'pub_date',
 
    'extra_context': extra_context,
 
    'template_name': 'podjango/cast/cast_detail.html',
 
}
...
 
@@ -51,24 +51,25 @@ urlpatterns = [
 
    url(r'^(?P<year>\d{4})/$', YearArchiveView.as_view(**info_dict), name='year-archive'),
 
    url(r'^all/$', custom_index, dict(info_dict, paginate_by=20), name='cast'),
 
    url(r'^query/$', query, name='query'),
 
    url(r'^feeds/ogg/$', OggCastFeed(), name='feed-ogg'),
 
    url(r'^feeds/mp3/$', Mp3CastFeed(), name='feed-mp3'),
 
    url(r'^feeds/$', view, name='feeds'),
 
]
 

	
 
if settings.DEBUG:
 
  from django.conf.urls.static import static
 
  urlpatterns += static('/', document_root='podjango/static')
 

	
 

	
 
def all_tags_by_use_amount():
 
    """Returns all tags with an added 'cnt' attribute (how many times used)
 

	
 
    Also sorts the tags so most-used tags appear first.
 
    """
 

	
 
    # tally use amount
 
    retval = []
 
    current = None
 
    for obj in CastTag.objects.filter(cast__pub_date__lte=datetime.now(),
 
                                      cast__isnull=False).order_by('label'):
 
        if current is not None and obj.id == current.id:
...
 
@@ -76,18 +77,19 @@ def all_tags_by_use_amount():
 
        else:
 
            if current is not None:
 
                retval.append(current)
 
            current = obj
 
            current.cnt = 1
 
    if current is not None:
 
        retval.append(current)
 

	
 
    # sort and return
 
    retval.sort(key=lambda x: -x.cnt)
 
    return retval
 

	
 

	
 
# The functions are passed to the context uncalled so they will be
 
# called for each web request.  If we want to only make these database
 
# queries a single time when a web server process begins, call both
 
# functions below (i.e. make both lines below end in '()')
 

	
 
extra_context['all_tags'] = all_tags_by_use_amount
conservancy/podjango/views.py
Show inline comments
...
 
@@ -12,37 +12,38 @@
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
 
# General Public License for more details.
 
#
 
# You should have received a copy of the GNU Affero General Public License
 
# along with this program in a file in the toplevel directory called
 
# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
 
#
 
from datetime import datetime
 
from functools import reduce
 
from operator import or_
 

	
 
from django.shortcuts import get_object_or_404, render
 
from django.views.generic.list import ListView
 

	
 
from .models import Cast, CastTag
 
from .models import CastTag
 

	
 

	
 
def OR_filter(field_name, objs):
 
    from django.db.models import Q
 
    return reduce(or_,
 
                  [Q(**{field_name: x.id}) for x in objs])
 

	
 

	
 
def last_name(person):
 
    return person.formal_name.rpartition(' ')[2]
 

	
 

	
 
def custom_index(request, queryset, *args, **kwargs):
 
    """Cast list view that allows scrolling and also shows an index by
 
    year.
 
    """
 

	
 
    kwargs = kwargs.copy()
 
    kwargs['extra_context'] = kwargs.get('extra_context', {}).copy()
 
    extra_context = kwargs['extra_context']
 

	
 
    date_field = kwargs['date_field']
 
    del kwargs['date_field']
 

	
...
 
@@ -66,47 +67,49 @@ def custom_index(request, queryset, *args, **kwargs):
 
    if authors or tags:
 
        query_string = '&'.join(['author=%s' % a.username for a in authors]
 
                                + ['tag=%s' % t.slug for t in tags])
 
        extra_context['query_string'] = query_string
 

	
 
    else:
 
        date_list = queryset.dates(date_field, 'year')
 
        extra_context['date_list'] = date_list
 

	
 
    # TODO
 
    return render(request, 'podjango/cast/cast_list.html', {'object_list': queryset})
 

	
 

	
 
def query(request):
 
    """Page to query the cast based on and tags
 
    """
 

	
 
    if request.GET:
 
        d = request.GET.copy()
 
        if 'authors' in d.getlist('all'):
 
            d.setlist('author', []) # remove author queries
 
            d.setlist('author', [])  # remove author queries
 
        if 'tags' in d.getlist('all'):
 
            d.setlist('tag', []) # remove tag queries
 
        d.setlist('all', []) # remove "all" from the query string
 
            d.setlist('tag', [])  # remove tag queries
 
        d.setlist('all', [])  # remove "all" from the query string
 

	
 
        base_url = '/cast/'
 
        if 'rss' in d:
 
            base_url = '/feeds/cast/'
 
            d.setlist('rss', []) # remove it
 
            d.setlist('rss', [])  # remove it
 

	
 
        query_string = d.urlencode()
 

	
 
        return relative_redirect(request, '%s%s%s' % (base_url, '?' if query_string else '', query_string))
 

	
 
    else:
 
        tags = CastTag.objects.all().order_by('label')
 
        return render(request, 'podjango/cast/query.html', {'tags': tags})
 

	
 

	
 
def relative_redirect(request, path):
 
    from django import http
 
    from django.conf import settings
 

	
 
    host = http.get_host(request)
 
    if settings.FORCE_CANONICAL_HOSTNAME:
 
        host = settings.FORCE_CANONICAL_HOSTNAME
 

	
 
    url = "%s://%s%s" % (request.is_secure() and 'https' or 'http', host, path)
 
    return http.HttpResponseRedirect(url)
0 comments (0 inline, 0 general)