Développement d'un flux de publications dynamiques avec Django REST Framework et Mini-Program

Architecture de la publication de contenu

Lors du développement d'une fonctionnalité de partage social dans une application, la structure des données envoyées par le client est cruciale pour la performance et la maintenance future. Voici l'évolution d'un format de données pour une publication incluant du texte et des images.

// Structure optimisée pour la gestion des fichiers
{
    "image_principale": "https://cdn.exemple.com/couverture.jpg",
    "description": "Exploration du développement mobile avec Django",
    "categorie_id": 10,
    "localisation": "Paris, France",
    "fichiers_media": [
        {
            "url": "https://cdn.exemple.com/img1.jpg",
            "cle_stockage": "img1.jpg"
        },
        {
            "url": "https://cdn.exemple.com/img2.jpg",
            "cle_stockage": "img2.jpg"
        }
    ]
}

L'inclusion de la cle_stockage (ou cos_key) permet au backend d'identifier précisément les fichiers dans le stockage objet (S3, COS, OSS) lors d'opérations de suppression ou de modification, sans avoir à parser l'URL.

Implémentation du Backend avec Django REST Framework

Pour gérer ces données, nous utilisons des sérialiseurs imbriqués pour valider à la fois la publictaion principale et les métadonnées des images associées.

from rest_framework import serializers, generics
from .models import Publication, MediaPublication

class MediaSerializer(serializers.ModelSerializer):
    class Meta:
        model = MediaPublication
        fields = ['url', 'cle_stockage']

class PublicationCreateSerializer(serializers.ModelSerializer):
    fichiers_media = MediaSerializer(many=True)

    class Meta:
        model = Publication
        exclude = ['auteur', 'vues', 'date_creation']

    def create(self, validated_data):
        # Extraction des données imbriquées
        medias = validated_data.pop('fichiers_media')
        
        # Création de l'instance principale
        instance_pub = Publication.objects.create(**validated_data)
        
        # Création groupée des médias liés
        MediaPublication.objects.bulk_create([
            MediaPublication(**item, publication=instance_pub) for item in medias
        ])
        
        return instance_pub

class PublicationView(generics.CreateAPIView):
    queryset = Publication.objects.all()
    serializer_class = PublicationCreateSerializer

    def perform_create(self, serializer):
        # Injection automatique de l'ID de l'utilisateur (simulé ici)
        serializer.save(auteur_id=1)

Optimisation de l'affichage : Le flux en cascade (Waterfall)

Pour l'interface utilisateur, le design en cascade est populaire. En Mini-Program, l'approche la plus flexible utilise Flexbox combiné à une logique de séparation des données (colonnes paires/impaires).

/* Styles CSS pour le flux */
.conteneur-cascade {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

.colonne {
    width: 48%;
}

.carte-item image {
    width: 100%;
    border-radius: 8rpx;
}
<!-- Structure WXML -->
<view class="conteneur-cascade">
    <view class="colonne">
        <block wx:for="{{listeData}}" wx:key="id">
            <view wx:if="{{index % 2 == 0}}" class="carte-item">
                <image src="{{item.image_principale}}" mode="widthFix"></image>
                <text&gt{{item.description}}</text>
            </view>
        </block>
    </view>

    <view class="colonne">
        <block wx:for="{{listeData}}" wx:key="id">
            <view wx:if="{{index % 2 != 0}}" class="carte-item">
                <image src="{{item.image_principale}}" mode="widthFix"></image>
                <text>{{item.description}}</text>
            </view>
        </block>
    </view>
</view>

Filtrage et Pagination Avancée

Pour améliorer les performances lors du défilement infini, il est préférable d'utiliser des filtres basés sur l'identifiant (ID) plutôt que sur un décalage (offset) pur, afin d'éviter le scan complet des tables SQL volumineuses.

from rest_framework.filters import BaseFilterBackend

class ScrollPaginationFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        dernier_id = request.query_params.get('lastId')
        direction = request.query_params.get('dir', 'down')
        
        if dernier_id:
            if direction == 'up':
                # Chargement des nouveaux éléments (refresh)
                return queryset.filter(id__gt=dernier_id).order_by('id')
            # Chargement des anciens éléments (pagination)
            return queryset.filter(id__lt=dernier_id)
        return queryset[:10]

Initialisation de données via Scripting ORM

Lors de la phase de test, l'utilisation d'un script autonome pour peupler la base de données est plus efficace que l'insertion manuelle. Il est nécessaire de configurer l'environnement Django au préalable.

import os
import django

# Configuration de l'environnement Django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mon_projet.settings")
django.setup()

from mon_app.models import Publication

def generer_donnees(n=20):
    for i in range(n):
        Publication.objects.create(
            description=f"Article de test numéro {i}",
            image_principale="https://cdn.exemple.com/test.png",
            auteur_id=1
        )
    print(f"Insertion de {n} entrées terminée.")

if __name__ == "__main__":
    generer_donnees()

La distinction entre sys.path (chemins de recherche des modules Python) et os.environ (variables système pour la configuration Django) est essentielle pour que le script puisse accéder aux modèles et à la base de données du projet.

Étiquettes: Django REST-Framework wechat-mini-program Python css-layout

Publié le 26 juillet à 05h59