Django

How to use PMKIN with Django

This guide walks you through integrating PMKIN into your Django application using GraphQL. All the code for this quick start guide is available in our Django quick start repository on GitHub.

Installation and Setup

Start by installing the necessary packages for your Django project:

pip install gql requests python-dotenv markdown
  • gql: A Python GraphQL client used to make queries to the PMKIN API.
  • requests: An HTTP library that gql is used to make network requests.
  • python-dotenv: A tool to load environment variables from a .env file.
  • markdown: A library to convert markdown text to HTML.

Set up your PMKIN API key as an environment variable. Create a .env file in your project root:

PMKIN_API_KEY=your_api_key_here

Ensure your Django application loads environment variables from the .env file. In your manage.py and wsgi.py files, add the following at the top:

import os
from dotenv import load_dotenv

load_dotenv()

Creating the GraphQL Client

Create a new file pmkin_client.py in your Django project (e.g., in a services directory):

import os
from gql import Client
from gql.transport.requests import RequestsHTTPTransport

pmkin_api_key = os.getenv('PMKIN_API_KEY')

if not pmkin_api_key:
    raise ValueError('PMKIN_API_KEY is not set.')

transport = RequestsHTTPTransport(
    url='https://pmkin-delivery.onrender.com/graphql',
    headers={
        'Authorization': f'Bearer {pmkin_api_key}'
    },
    verify=True,
    retries=3,
)

client = Client(
    transport=transport,
    fetch_schema_from_transport=True,
)

Listing Documents

Create a new Django view to list the documents. In your app's views.py file:

from django.shortcuts import render
from gql import gql
from .pmkin_client import client  # Adjust the import path as necessary

GET_DOCUMENTS = gql('''
    query GetDocuments {
        documents(includeDrafts: false) {
            id
            metaDescription
            slug
            title
        }
    }
''')

def blog_list(request):
    try:
        response = client.execute(GET_DOCUMENTS)
        documents = response['documents']
    except Exception as e:
        documents = []
        # Handle exceptions as needed, e.g., log the error
    return render(request, 'blog_list.html', {'documents': documents})

Create a template blog_list.html in your templates directory:

<!DOCTYPE html>
<html>
<head>
    <title>Blog Posts</title>
</head>
<body>
    <h1>Blog Posts</h1>
    {% for doc in documents %}
    <article>
        <h2><a href="{% url 'blog_detail' slug=doc.slug %}">{{ doc.title }}</a></h2>
        <p>{{ doc.metaDescription }}</p>
    </article>
    {% empty %}
    <p>No blog posts available.</p>
    {% endfor %}
</body>
</html>

Update your urls.py to include the new view:

from django.urls import path
from . import views

urlpatterns = [
    path('blog/', views.blog_list, name='blog_list'),
    path('blog/<slug:slug>/', views.blog_detail, name='blog_detail'),
]

Rendering Document Content

Add the blog_detail view to your views.py:

from django.shortcuts import render
from django.http import Http404
from gql import gql
from markdown import markdown
from .pmkin_client import client  # Adjust the import path as necessary

GET_DOCUMENT = gql('''
    query GetDocument($slug: String!) {
        documentBySlug(slug: $slug) {
            id
            markdown
            metaDescription
            metaTitle
            title
        }
    }
''')

def blog_detail(request, slug):
    variables = {'slug': slug}
    try:
        response = client.execute(GET_DOCUMENT, variable_values=variables)
        document = response.get('documentBySlug')
        if not document:
            raise Http404('Document not found')
        document['html_content'] = markdown(document['markdown'])
    except Exception as e:
        raise Http404('An error occurred while fetching the document.')
    return render(request, 'blog_detail.html', {'document': document})

Create the template blog_detail.html:

<!DOCTYPE html>
<html>
<head>
    <title>{{ document.metaTitle|default:document.title }}</title>
    <meta name="description" content="{{ document.metaDescription }}">
</head>
<body>
    <article>
        <h1>{{ document.title }}</h1>
        {{ document.html_content|safe }}
    </article>
</body>
</html>

Handling Metadata

To dynamically generate metadata for each blog post, we've included the metaTitle and metaDescription fields from the PMKIN API. We use these values in the template to set the page title and meta description.

Error Handling

In the views, we've added basic error handling:

  • blog_list: If an error fetching documents, an empty list is displayed.
  • blog_detail: If the document is not found or an error occurs, a 404 error is raised.

You can customize the error handling to fit your application's needs, such as logging errors or displaying custom error pages.

This Setup Provides a Solid Foundation

Following this guide, you've integrated PMKIN with your Django application using GraphQL. You can expand on this by adding features like pagination, categories, or search functionality.

Additional Notes

  • Pagination: Use Django's built-in pagination or implement GraphQL pagination if supported by the PMKIN API.
  • Categories/Tags: If the PMKIN API provides categories or tags, you can include them in your queries and templates.
  • Search Functionality: Implement search by querying the PMKIN API with search parameters.

Environment Variables and Security

Ensure that your .env file is included in your .gitignore to prevent it from being checked into version control. Set environment variables securely in production using your hosting provider's recommended practices.

Fetching Data Efficiently

Consider caching responses or using Django's caching mechanisms to reduce the number of API calls, especially for data that doesn't change frequently.