How to do it...

We will augment the Bulletin model and add an RSS feed to it. We will be able to filter the RSS feed by type or category so that it is possible to only subscribe to the bulletins that are, for example, offering used books:

  1. In the models.py file of this app, add the Category model, like so:
# bulletin_board/models.py
# ...

class Category(models.Model):
class Meta:
verbose_name = _("Category")
verbose_name_plural = _("Categories")

title = models.CharField(_("Title"), max_length=200)

def __str__(self):
return self.title

  1. We'll then augment the Bulletin model to add a foreign key relationship with Category, and to apply the UrlMixin we created in the Creating a model mixin with URL-related methods recipe in Chapter 2, Database Structure and Modeling, as follows:
# bulletin_board/models.py
# import ...
from django.urls import reverse

from utils.models import CreationModificationDateMixin, UrlMixin

# ...

class Bulletin(CreationModificationDateMixin, UrlMixin):
class Meta:
verbose_name = _("Bulletin")
verbose_name_plural = _("Bulletins")
ordering = ("-created", "title",)

category = models.ForeignKey(Category,
null=True,
verbose_name=_("Category"),
on_delete=models.SET_NULL)
# ...

def get_url_path(self):
try:
path = reverse("bulletin_detail",
kwargs={"pk": self.pk})
except:
# the apphook is not attached yet
return ""
else:
return path

  1. Migrate the bulletin_board app to update the database according to the model changes.
  2. Then, create BulletinFilterForm that allows the visitor to filter the bulletins by type and category, as follows:
# bulletin_board/forms.py
# ...other imports...
from django import forms
from django.utils.translation import ugettext_lazy as _

from .models import Bulletin, Category, TYPE_CHOICES

TYPE_FILTER_CHOICES = (("", "----------"),) + TYPE_CHOICES


class BulletinFilterForm(forms.Form):
bulletin_type = forms.ChoiceField(
label=_("Bulletin Type"),
required=False,
choices=TYPE_FILTER_CHOICES)
category = forms.ModelChoiceField(
label=_("Category"),
required=False,
queryset=Category.objects.all())

# ...
  1. Add a feeds.py file with the BulletinFeed class, as shown here:
# bulletin_board/feeds.py
from django.contrib.syndication.views import Feed
from django.urls import reverse

from .models import Bulletin, TYPE_CHOICES
from .forms import BulletinFilterForm


class BulletinFeed(Feed):
description_template =
"bulletin_board/feeds/bulletin_description.html"

def get_object(self, request, *args, **kwargs):
form = BulletinFilterForm(data=request.GET)
obj = {}
if form.is_valid():
obj = {"query_string": request.META["QUERY_STRING"]}
for field in ["bulletin_type", "category"]:
value = form.cleaned_data.get(field, None)
obj[field] = value
return obj

def title(self, obj):
title_parts = ["Bulletin Board"]

# add type "Searching" or "Offering"
type_key = obj.get("bulletin_type", False)
type = dict(TYPE_CHOICES).get(type_key, False)
if type_key else ""
if type:
title_parts.append(type)

# add category
category = obj.get("category", False)
if category:
title_parts.append(category.title)

return " - ".join(title_parts)

def link(self, obj):
return self.get_named_url("bulletin-list", obj)

def feed_url(self, obj):
return self.get_named_url("bulletin-rss", obj)

@staticmethod
def get_named_url(name, obj):
url = reverse(name)
qs = obj.get("query_string", False)
if qs:
url = f"{url}?{qs}"
return url

def item_pubdate(self, item):
return item.created

def items(self, obj):
type = obj.get("bulletin_type", False)
category = obj.get("category", False)

qs = Bulletin.objects.order_by("-created")
if type:
qs = qs.filter(bulletin_type=type).distinct()
if category:
qs = qs.filter(category=category).distinct()
return qs[:30]
  1. Create a template for the bulletin description that will be provided in the feed, as shown here:
{# templates/bulletin_board/feeds/bulletin_description.html #} 
{% if obj.image %}
<p>
<a href="{{ obj.get_url }}">
<img src="{{ MEDIA_URL }}{{ obj.image.url }}"
alt="" /></a>
</p>
{% endif %}
<p>{{ obj.description }}</p>

  1. Create a URL configuration for the bulletin_board app, or update the existing one, and include it in the root URL configuration. The result should include the new feed URL rule, as follows:
# templates/bulletin_board/urls.py
from django.urls import path, reverse_lazy

from .feeds import BulletinFeed
from .views import (BulletinList, BulletinDetail)


urlpatterns = [
path('', BulletinList.as_view(),
name='bulletin-list'),
path('<int:pk>/', BulletinDetail.as_view(),
name='bulletin-detail'),
path('rss/', BulletinFeed(),
name='bulletin-rss'),
# ...
]
  1. You will also need views for the filterable list and details of the bulletins:
# bulletin_board/views.py
# ...other imports...
from django.views.generic import ListView, DetailView

from .models import Bulletin

# ...

class BulletinList(ListView):
model = Bulletin


class BulletinDetail(DetailView):
model = Bulletin

# ...
  1. Next, add a Bulletins listing page template, including the RSS feed link, as follows:
{# templates/bulletin_board/bulletin_list.html #}
{% extends "base.html" %}
{% load i18n %}

{% block content %}
<h2>{% trans "Bulletins" %}</h2>
{% if bulletin_list.count == 0 %}
<p>
No bulletins to show! Why don't you
<a href="{% url "bulletin-create" %}">
create a new bulletin</a>?
</p>
{% else %}
<dl class="bulletin-list">
{% for bulletin in bulletin_list %}
<dt>
<a href="{% url "bulletin-detail" pk=bulletin.pk %}">
{{ bulletin.title }}</a>
{% if request.user.is_authenticated %}
<a class="btn btn-outline-secondary btn-sm"
href="{% url "bulletin-edit" pk=bulletin.pk %}">
Edit</a>
{% endif %}
</dt>
<dd>
{% if bulletin.description %}
<p>{{ bulletin.description }}</p>
{% endif %}
</dd>
{% endfor %}
</dl>
<p>
<a href="{% url "bulletin-rss" %}?{{ request.META.QUERY_STRING }}">
RSS Feed</a>
</p>
{% endif %}
{% endblock %}
  1. Finally, add a Bulletins detail page template, which can reuse the same bulletin_description.html template, as shown here:
{# templates/bulletin_board/bulletin_detail.html #}
{% extends "base.html" %}
{% load i18n %}

{% block content %}
<h1>
{{ object.bulletin_type|capfirst }}:
<strong>{{ object.title }}</strong>
{% if request.user.is_authenticated %}
<a class="btn btn-outline-secondary btn-sm"
href="{% url "bulletin-edit" pk=bulletin.pk %}">Edit</a>
{% endif %}
</h1>

{% if category %}
<p><em>{{ object.category.title }}</em></p>
{% endif %}

{% include "bulletin_board/feeds/bulletin_description.html" with obj=object %}

<h3>Contact {{ object.contact_person }}</h3>

{% if object.phone or object.email %}
{% if object.phone %}
<p>Phone: {{ object.phone }}</p>
{% endif %}

{% if object.email %}
<p>Email: <a href="mailto:{{ object.email }}?subject={{ object.title|escape }}">
{{ object.email }}</p>
{% endif %}
{% endif %}

<p><a href="{% url "bulletin-list" %}">Back to Listing</a></p>
{% endblock %}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.246.203