Je souhaite développer une application Django permettant aux utilisateurs de créer des publications avec plusieurs images. Les utilisateurs doivent pouvoir télécharger jusqu’à 8 images dans une seule publication, qui seront prévisualisées avant la soumission. Sur la page d’accueil, une seule image par publication sera affichée avec un titre et une description. Lorsqu’un utilisateur clique sur l’image ou le lien “voir plus”, il doit accéder à une vue détaillée présentant toutes les images et les informations complètes de la publication.
myproject/
│
├── myproject/
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
├── post/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ ├── views.py
│ └── templates/
│ └── post/
│ ├── post_create.html
│ ├── home.html
│ └── post_detail.html
│
├── media/
│ └── images/
│
├── manage.py
└── requirements.txt
. Modèles (models.py
)
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
def __str__(self):
return self.title
class Image(models.Model):
post = models.ForeignKey(Post, related_name='images', on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/')
def __str__(self):
return f"Image for {self.post.title}"
Formulaires (forms.py
)
from django import forms
from .models import Post, Image
from django.forms import inlineformset_factory
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'description']
class ImageForm(forms.ModelForm):
class Meta:
model = Image
fields = ['image']
ImageFormSet = inlineformset_factory(Post, Image, form=ImageForm, extra=1, can_delete=True)
Vues (views.py
)
from django.shortcuts import render, redirect, get_object_or_404
from .models import Post, Image
from .forms import PostForm, ImageFormSet
def post_create(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
image_formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.none())
if post_form.is_valid() and image_formset.is_valid():
post = post_form.save()
images = image_formset.save(commit=False)
for image in images:
image.post = post
image.save()
return redirect('home')
else:
post_form = PostForm()
image_formset = ImageFormSet(queryset=Image.objects.none())
return render(request, 'post/post_create.html', {
'post_form': post_form,
'image_formset': image_formset
})
def home(request):
posts = Post.objects.all()
return render(request, 'post/home.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
images = post.images.all()
# Débogage
print(f"Post: {post.title}")
for image in images:
print(f"Image URL: {image.image.url}")
return render(request, 'post/post_detail.html', {'post': post})
URL Configuration (urls.py
dans post/
)
# post/urls.py
from django.urls import path
from .views import post_create, home, post_detail
urlpatterns = [
path('', home, name='home'),
path('post/create/', post_create, name='post_create'),
path('post/<int:pk>/', post_detail, name='post_detail'),
]
Templates
post_create.html
<!-- post/templates/post/post_create.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create Post</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.container { max-width: 800px; margin: auto; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; }
input[type="text"], textarea { width: 100%; padding: 10px; box-sizing: border-box; }
.image-preview { display: flex; flex-wrap: wrap; gap: 10px; }
.image-preview img { max-width: 100px; max-height: 100px; }
.form-group input[type="submit"] { padding: 10px 20px; }
.nav-links { margin-bottom: 20px; }
.nav-links a { margin-right: 10px; }
</style>
</head>
<body>
<div class="container">
<div class="nav-links">
<a href="{% url 'home' %}">Home</a>
<a href="{% url 'post_create' %}">Create Post</a>
</div>
<h1>Create a New Post</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ post_form.as_p }}
{{ image_formset.management_form }}
{% for form in image_formset %}
{{ form.as_p }}
{% endfor %}
<button type="submit">Publish</button>
<div class="form-group">
<label for="images">Upload Images (Up to 8)</label>
<input type="file" name="image" id="images" multiple>
</div>
<input type="submit" value="Submit">
</form>
</div>
</body>
</html>
home.html
<!-- post/templates/post/home.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.container { max-width: 800px; margin: auto; }
.post { border: 1px solid #ddd; padding: 15px; margin-bottom: 20px; border-radius: 5px; background-color: #f9f9f9; }
.post img { max-width: 100%; height: auto; border-radius: 5px; }
.post h2 a { text-decoration: none; color: #333; }
.nav-links { margin-bottom: 20px; }
.nav-links a { margin-right: 10px; }
</style>
</head>
<body>
<div class="container">
<div class="nav-links">
<a href="{% url 'home' %}">Home</a>
<a href="{% url 'post_create' %}">Create Post</a>
</div>
<h1>All Posts</h1>
{% for post in posts %}
<div class="post">
<h2><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></h2>
{% if post.images.exists %}
<img src="{{ post.images.first.image.url }}" alt="Image for {{ post.title }}">
{% endif %}
<p>{{ post.description }}</p>
</div>
{% empty %}
<p>No posts available.</p>
{% endfor %}
</div>
</body>
</html>
post_detail.html
####
<!-- post/templates/post/post_detail.html-->
<!DOCTYPE html>
<html>
<head>
<title>{{ post.title }}</title>
</head>
<body>
<h1>{{ post.title }}</h1>
<p>{{ post.description }}</p>
<div>
<div>
{% for image in post.images.all %}
<img src="{{ image.image.url }}" alt="Image for {{ post.title }}" style="max-width: 100%; height: auto; margin-bottom: 10px;">
{% endfor %}
</div>
</div>
<a href="{% url 'home' %}">Back to Home</a>
</body>
</html>
chattona/urls.py (url principal )
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('post.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)