每天40分玩转Django:实操图片分享社区

devtools/2024/12/27 15:15:45/

实操图片分享社区

一、今日学习内容概述

学习模块重要程度主要内容
模型设计⭐⭐⭐⭐⭐图片/用户模型、关系设计
视图开发⭐⭐⭐⭐⭐上传/展示/交互功能
用户系统⭐⭐⭐⭐⭐注册/登录/权限控制
前端交互⭐⭐⭐⭐界面设计/Ajax操作

二、模型设计

python"># models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from PIL import Image
import uuiddef 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']

三、视图实现

python"># 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.userpost.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 = postcomment.user = request.usercomment.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 = Falseelse:post.likes.add(request.user)liked = Truereturn JsonResponse({'liked': liked,'likes_count': post.likes.count()})

四、表单设计

python"># forms.py
from django import forms
from .models import Post, Comment, Profileclass PostForm(forms.ModelForm):class Meta:model = Postfields = ['image', 'caption']widgets = {'caption': forms.Textarea(attrs={'rows': 3}),}class CommentForm(forms.ModelForm):class Meta:model = Commentfields = ['text']widgets = {'text': forms.Textarea(attrs={'rows': 2,'placeholder': '写下你的评论...'})}class ProfileForm(forms.ModelForm):class Meta:model = Profilefields = ['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);}});}
});

八、常见功能扩展

  1. 图片过滤器
python">from PIL import Image, ImageEnhancedef 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
  1. 图片标签系统
python">class Tag(models.Model):name = models.CharField(max_length=50, unique=True)def __str__(self):return self.nameclass Post(models.Model):# ... 其他字段 ...tags = models.ManyToManyField(Tag, blank=True)
  1. 收藏功能
python">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)

通过本章学习,你应该能够:

  1. 设计和实现图片分享系统
  2. 处理用户认证和权限
  3. 实现图片上传和处理
  4. 开发社交互动功能

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!


http://www.ppmy.cn/devtools/145850.html

相关文章

mybatis/mybatisplus

一、mybatis 1.什么是 持久化框架。通过XML或注解的方式将实体类和SQL语句进行映射&#xff0c;开发者快速进行CRUD操作。 2.核心组件 (1)SqlSessionFactory 创建SqlSession实例。用于执行SQL操作 。代码 String resource "org/mybatis/example/mybatis-config.xml&q…

存储块的获取与释放

目录 获取存储块 释放存储块 设计实现 获取存储块 有空闲存储块&#xff0c;直接取出空闲块&#xff1b; 无空闲存储块&#xff0c;任务进入等待队列。 释放存储块 无任务等待&#xff0c;插入到空闲链表&#xff1b; 有任务等待&#xff0c;释放等待队列头部的任务。 设计实现…

Docker 部署 plumelog 最新版本 实现日志采集

1.配置plumelog.yml version: 3 services:plumelog:#此镜像是基于plumelog-3.5.3版本image: registry.cn-hangzhou.aliyuncs.com/k8s-xiyan/plumelog:3.5.3container_name: plumelogports:- "8891:8891"environment:plumelog.model: redisplumelog.queue.redis.redi…

`we_chat_union_id IS NOT NULL` 和 `we_chat_union_id != ‘‘` 这两个条件之间的区别

文章目录 1、什么是空字符串&#xff1f;2、两个引号之间加上空格 好的&#xff0c;我们来详细解释一下 we_chat_union_id IS NOT NULL 和 we_chat_union_id ! 这两个条件之间的区别&#xff0c;以及它们在 SQL 查询中的作用&#xff1a; 1. we_chat_union_id IS NOT NULL 含…

KVM虚拟机管理脚本

思路&#xff1a; 在/opt/kvm下创建一个磁盘文件&#xff0c;做差异镜像&#xff0c;创建一个虚拟机配置文件&#xff0c;做虚拟机模版 [rootnode01 ~]# ls /opt/kvm/ vm_base.qcow2 vm_base.xml创建虚拟机的步骤&#xff1a;首先创建虚拟机的差异镜像&#xff0c;然后复制虚…

学习记录—正则表达式-基本语法

正则表达式简介-《菜鸟教程》 正则表达式是一种用于匹配和操作文本的强大工具&#xff0c;它是由一系列字符和特殊字符组成的模式&#xff0c;用于描述要匹配的文本模式。 正则表达式可以在文本中查找、替换、提取和验证特定的模式。 本期内容将介绍普通字符&#xff0c;特殊…

http 请求总结get

关于get请求传递body的问题 错误代码 有400 , 415 等情况 <!doctype html><html lang"zh"><head><title>HTTP Status 400 – 错误的请求</title><style type"text/css">body {font-family:Tahoma,Arial,sans-seri…

求两大数和

题目描述 大数加法问题 大数的输入不能简单定义整数变量&#xff0c;因为存不下这么大的数&#xff0c;要采用字符串输入方式&#xff0c;把大数存入到字符串中&#xff0c;按照数码位个位对齐&#xff0c;逐个数码位相加 数字字符做对应数值的加法规则 58 > (5-0)(8…