每天40分玩转Django:实操图片分享社区
实操图片分享社区
一、今日学习内容概述
学习模块 | 重要程度 | 主要内容 |
---|---|---|
模型设计 | ⭐⭐⭐⭐⭐ | 图片/用户模型、关系设计 |
视图开发 | ⭐⭐⭐⭐⭐ | 上传/展示/交互功能 |
用户系统 | ⭐⭐⭐⭐⭐ | 注册/登录/权限控制 |
前端交互 | ⭐⭐⭐⭐ | 界面设计/Ajax操作 |
二、模型设计
# models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from PIL import Image
import uuid
def image_upload_path(instance, filename):
ext = filename.split('.')[-1]
return f'images/{uuid.uuid4()}.{ext}'
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField('个人简介', max_length=500, blank=True)
avatar = models.ImageField('头像', upload_to='avatars/', blank=True)
following = models.ManyToManyField('self', symmetrical=False, related_name='followers')
def __str__(self):
return f'{self.user.username}的个人资料'
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
image = models.ImageField('图片', upload_to=image_upload_path)
caption = models.TextField('描述', max_length=1000)
created_at = models.DateTimeField('创建时间', auto_now_add=True)
likes = models.ManyToManyField(User, related_name='liked_posts', blank=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return f'{self.user.username}的图片 - {self.created_at}'
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# 处理图片大小
with Image.open(self.image.path) as img:
if img.height > 1080 or img.width > 1920:
output_size = (1920, 1080)
img.thumbnail(output_size)
img.save(self.image.path)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, on_delete=models.CASCADE)
text = models.TextField('评论内容')
created_at = models.DateTimeField('创建时间', auto_now_add=True)
class Meta:
ordering = ['created_at']
三、视图实现
# views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.core.paginator import Paginator
from .models import Post, Comment, Profile
from .forms import PostForm, CommentForm
@login_required
def upload_post(request):
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
return redirect('post_detail', post.id)
else:
form = PostForm()
return render(request, 'posts/post_create.html', {'form': form})
def post_list(request):
posts_list = Post.objects.select_related('user').prefetch_related('comments')
paginator = Paginator(posts_list, 12)
page = request.GET.get('page')
posts = paginator.get_page(page)
return render(request, 'posts/post_list.html', {'posts': posts})
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id)
comments = post.comments.select_related('user')
if request.method == 'POST':
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = post
comment.user = request.user
comment.save()
return redirect('post_detail', post_id=post.id)
else:
comment_form = CommentForm()
return render(request, 'posts/post_detail.html', {
'post': post,
'comments': comments,
'comment_form': comment_form
})
@require_POST
@login_required
def like_post(request):
post_id = request.POST.get('post_id')
post = get_object_or_404(Post, id=post_id)
if request.user in post.likes.all():
post.likes.remove(request.user)
liked = False
else:
post.likes.add(request.user)
liked = True
return JsonResponse({
'liked': liked,
'likes_count': post.likes.count()
})
四、表单设计
# forms.py
from django import forms
from .models import Post, Comment, Profile
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['image', 'caption']
widgets = {
'caption': forms.Textarea(attrs={'rows': 3}),
}
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text']
widgets = {
'text': forms.Textarea(attrs={
'rows': 2,
'placeholder': '写下你的评论...'
})
}
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['bio', 'avatar']
五、模板实现
<!-- templates/posts/post_list.html -->
{% extends 'base.html' %}
{% block content %}
<div class="container mt-4">
<div class="row">
{% for post in posts %}
<div class="col-md-4 mb-4">
<div class="card">
<a href="{{ post.get_absolute_url }}">
<img src="{{ post.image.url }}" class="card-img-top" alt="{{ post.caption }}">
</a>
<div class="card-body">
<div class="d-flex align-items-center mb-2">
<img src="{{ post.user.profile.avatar.url }}"
class="rounded-circle me-2"
width="32" height="32">
<h6 class="card-title mb-0">{{ post.user.username }}</h6>
</div>
<p class="card-text text-truncate">{{ post.caption }}</p>
<div class="d-flex justify-content-between">
<button class="btn btn-sm like-button"
data-post-id="{{ post.id }}"
data-liked="{{ user in post.likes.all|yesno:'true,false' }}">
<i class="fas fa-heart"></i>
<span class="likes-count">{{ post.likes.count }}</span>
</button>
<small class="text-muted">
{{ post.created_at|timesince }}前
</small>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% include 'includes/pagination.html' with page=posts %}
</div>
{% endblock %}
<!-- templates/posts/post_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="container mt-4">
<div class="row">
<div class="col-md-8">
<img src="{{ post.image.url }}" class="img-fluid">
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<div class="d-flex align-items-center">
<img src="{{ post.user.profile.avatar.url }}"
class="rounded-circle me-2"
width="32" height="32">
<h6 class="mb-0">{{ post.user.username }}</h6>
</div>
</div>
<div class="card-body">
<p>{{ post.caption }}</p>
<hr>
<div class="comments-section">
{% for comment in comments %}
<div class="comment mb-2">
<strong>{{ comment.user.username }}</strong>
{{ comment.text }}
<small class="text-muted d-block">
{{ comment.created_at|timesince }}前
</small>
</div>
{% endfor %}
</div>
{% if user.is_authenticated %}
<form method="post" class="mt-3">
{% csrf_token %}
{{ comment_form }}
<button type="submit" class="btn btn-primary btn-sm mt-2">
发表评论
</button>
</form>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
六、流程图
七、JavaScript交互
// static/js/main.js
document.addEventListener('DOMContentLoaded', function() {
// 图片点赞功能
document.querySelectorAll('.like-button').forEach(button => {
button.addEventListener('click', function() {
const postId = this.dataset.postId;
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
fetch('/posts/like/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': csrftoken
},
body: `post_id=${postId}`
})
.then(response => response.json())
.then(data => {
const icon = this.querySelector('i');
const count = this.querySelector('.likes-count');
if (data.liked) {
icon.classList.add('text-danger');
} else {
icon.classList.remove('text-danger');
}
count.textContent = data.likes_count;
});
});
});
// 图片上传预览
const imageInput = document.querySelector('input[type="file"]');
if (imageInput) {
imageInput.addEventListener('change', function() {
const file = this.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
document.querySelector('#preview-image').src = e.target.result;
}
reader.readAsDataURL(file);
}
});
}
});
八、常见功能扩展
- 图片过滤器
from PIL import Image, ImageEnhance
def apply_filter(image, filter_name):
"""应用图片滤镜"""
img = Image.open(image)
if filter_name == 'grayscale':
return img.convert('L')
elif filter_name == 'brightness':
enhancer = ImageEnhance.Brightness(img)
return enhancer.enhance(1.5)
# 添加更多滤镜...
return img
- 图片标签系统
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Post(models.Model):
# ... 其他字段 ...
tags = models.ManyToManyField(Tag, blank=True)
- 收藏功能
class Collection(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
posts = models.ManyToManyField(Post, related_name='collections')
name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
通过本章学习,你应该能够:
- 设计和实现图片分享系统
- 处理用户认证和权限
- 实现图片上传和处理
- 开发社交互动功能
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!