雁过留声 发表于 2024-12-27 19:44:09

天天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=)
   
    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 %}
六、流程图

https://i-blog.csdnimg.cn/direct/72a202a826f84185893b3a93e9b3522a.png
七、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('').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');
    if (imageInput) {
      imageInput.addEventListener('change', function() {
            const file = this.files;
            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大礼包。末了,祝您早日实现财务自由,还请给个赞,谢谢!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 天天40分玩转Django:实操图片分享社区