Django 实现瀑布流

需求分析

现在是 "图片为王"的时代,在浏览一些网站时,经常会看到类似于这种满屏都是图片。图片大小不一,却按空间排列,就这是瀑布流布局。

  • 以瀑布流形式布局,从数据库中取出图片
  • 每次取出等量(7 条)的图片,加载到页面
  • 当滑轮滚动到最底端时,自动再加载图片

实现流程

  • 以包形式管理模型
  • 将图片自动上传到静态文件 static
  • 前端页面每行排列四张图片(四个 div )
  • 当页面加载时,以 ajax 形式自动向后台发送请求,获取图片数据,再用 js 循环生成 img 标签添加到每个 div 中
  • JS 循环图片信息列表,将当前循环元素的索引与每行排列的图片数目(4张)求余数,再利用余数定位每个 div 标签

模型设计

在这里,我以包的形式管理模型 models,编写 app/models/video/img_models.py

from django.db import models


class Img(models.Model):
    """
    upload_to: 上传文件地址
    """
    src = models.FileField(max_length=64, verbose_name='图片地址', upload_to='app/static/app/upload')
    title = models.CharField(max_length=64, verbose_name='标题')
    summary = models.CharField(max_length=128, verbose_name='简介')

    class Meta:
        verbose_name_plural = '图片'

    def __str__(self):
        return self.title

视图函数

编写 app/views.py

from django.shortcuts import render
from django.http import JsonResponse
from app.models.video.img_models import Img


def img(request):

    return render(request, 'app/img.html')


def getImgs(request):
    nid = request.GET.get('nid')
    print(nid)

    # nid 第一次取为 0,每次取 7 条
    last_position_id = int(nid) + 7
    postion_id = str(last_position_id)

    # 获取 0 < id < 7 的数据
    img_list = Img.objects.filter(id__gt=nid, id__lt=postion_id).values('id', 'title', 'src')
    img_list = list(img_list)   # 将字典格式转换为列表形式
    ret = {
        'status': True,
        'data': img_list
    }

    return JsonResponse(ret)

在后台取出符合条件的数据,然后打包成 JSON 格式数据,前端模板再通过 jQuery 将其循环生成 img 标签,并添加到 div 标签中。

模板

编写 app/templates/app/img.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>瀑布流</title>
    <style type="text/css">
        .box1{
            width: 1000px;
            margin: 0 auto;
        }

        .box1 .item{
            width: 25%;
            float: left;
        }

        .item img{
            width: 100%;
        }
    </style>
</head>
<body>
    <h1>瀑布流</h1>
    <div class="box1" id="container">
        <div class="item">

        </div>

        <div class="item">

        </div>

        <div class="item">

        </div>

        <div class="item">

        </div>
    </div>


    <script src="{% static 'app/jquery/jquery-3.1.1.js' %}"></script>
    <script>
        $(function () {
            initImg();
            scroll();
        });

        NID = 0;
        LASTPOSTION = 3;    // 循环最后那个的位置
        function initImg() {
            $.ajax({
                url: '/app/getImgs/',
                type: 'GET',
                data: {nid: NID},
                dataType: 'JSON',
                success: function (arg) {
                    if (arg.status){
                       var img_list = arg.data;
                       $.each(img_list, function (index, value) {
                          var n = (index + LASTPOSTION + 1) % 4;
{#                          console.log(n);    // 0、1 、2 、3    一直为 0、1 、2 、3#}
                          var img = document.createElement('img');
                          img.src = '/' + value.src;    //  app/static/app/upload/7.jpg

                           // 也就是给第一、二、三、四给 div 添加 img 标签,eq(0) 为第一个
                          $('#container').children().eq(n).append(img);
                          if (index + 1 == img_list.length){
                              console.log(n, value.id);
                              LASTPOSTION = n;
{#                              NID = value.id;#}
                          }
                       });
                    }
                }
            })
        }

        // 监听滑轮
        $(window).scroll(function () {
            // 文档高度
            var doc_height = $(document).height();
            // 窗口高度
            var window_height = $(window).height();
            // 滑轮高度
            var scroll_height = $(window).scrollTop();
            if (window_height + scroll_height == doc_height){
                initImg();
            }
        })

        
    </script>
</body>
</html>

settings 配置

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        # templates 设置
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

# 因为让模板能够找到 static 中图片,添加了 /app
STATIC_URL = '/app/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'app', 'static'),
)


TEMPLATE_DIRS = (os.path.join(BASE_DIR, 'app', 'templates'),)

urlconf 配置

这是我的 app/urls.py

# Project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app/', include('app.urls')),
]

# app/urls.py
from django.urls import path
from app import views

urlpatterns = [
    path('img/', views.img, name='img'),
    path('getImgs/', views.getImgs, name='getImgs'),
]

包管理模型

整个项目的模型部分,以包的形式管理,有些功能部分单独设计模型文件,因此要在包文件中导入相应模型。

编写 app/models/video/__init__.py

from app.models.video.img_models import Img

使用对象封装全局变量

在上面 JS 代码中,我们使用了全局变量,实际开发中应该尽量避免使用全局变量,在这里用对象将其封装。

// 全局变量封装
$(function () {
    var obj = new ScrollImg();   // 定义一个对象
    obj.fetchImg();         
    obj.scrollEvent();
});

// 对象 ScrollImg
function ScrollImg() {
    // 将之前的全局变量封装在对象内部,仅其内部能使用
    this.NID = 0;       
    this.LASTPOSITION = 3;

    // 向后台发送 ajax 请求,获取图片信息
    this.fetchImg = function () {
        var that = this;
        $.ajax({
            url: '/app/getImgs/',
            type: 'GET',
            data: {nid: that.NID},
            dataType: 'JSON',
            success: function (arg) {
                var img_list = arg.data;
                $.each(img_list, function (index, value) {
                    var n = (index + that.LASTPOSITION + 1) % 4;
                    var img = document.createElement('img');
                    img.src = '/' + value.src;

                    $('#container').children().eq(n).append(img);
                    if (index + 1 == img_list.length) {
                        that.LASTPOSITION = n;

                        // 每取完一次,便把最后那条的 id 赋值给 NID 传到后台,再根据这个条件取 7 条数据
                        that.NID = value.id;
                    }
                });
            }
        })
    };

    this.scrollEvent = function () {
        var that = this;

        // 监听滑轮,当滑轮高度+窗口高度==文档高度时,即表示滑轮已经滑动到最底部,再执行 fetchImg() 函数,再从数据库取出数据
        $(window).scroll(function () {
            var scroll_height = $(window).scrollTop();
            var window_height = $(window).height();
            var doc_height = $(document).height();
            if (scroll_height + window_height == doc_height ) {
                that.fetchImg();
            }
        })
    }
}

这是整个项目大致分布:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mYAM6WY5-1679406971121)(https://raw.githubusercontent.com/hj1933/img/master/iimg/%E7%80%91%E5%B8%83%E6%B5%81.gif)]

参考博客

  • 小功能瀑布流的实现

  • django实现瀑布流、组合搜索、阶梯评论、验证码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/3059.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Educational Codeforces Round 145 (Rated for Div. 2) (A~E)

Problem - B - Codeforces 思路&#xff1a; 我们选择长度后&#xff0c;其特定长度会构成一个正方形&#xff0c;因为点与点距离大于1&#xff0c;所以偶数的正方形里面只能包含偶数的正方形&#xff0c;奇数的包含奇数。计算每个长度容纳最大点数&#xff1a; 发现cnt[0]1,…

WPF毛笔字实现过程

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Python中生产者消费者模型

Python生产者消费者模型 一、消费模式 生产者消费者模式 是Controlnet网络中特有的一种传输数据的模式。用于两个CPU之间传输数据&#xff0c;即使是不同类型同一厂家的CPU也可以通过设置来使用。 二、传输原理 类似与点对点传送&#xff0c;又略有不同&#xff0c;一个生产…

能把爬虫讲的这么透彻的,没有20年功夫还真不行【0基础也能看懂】

前言 可以说很多人学编程&#xff0c;不玩点爬虫确实少了很多意思&#xff0c;不管是业余、接私活还是职业爬虫&#xff0c;爬虫世界确实挺精彩的。 今天来给大家浅谈一下爬虫&#xff0c;目的是让准备学爬虫或者刚开始起步的小伙伴们&#xff0c;对爬虫有一个更深更全的认知…

chatGPT爆火,什么时候中国能有自己的“ChatGPT“

目录 引言 一、ChatGPT爆火 二、中国何时能有自己的"ChatGPT" 三、为什么openai可以做出chatGPT? 四、结论 引言 随着人工智能技术的不断发展&#xff0c;自然语言处理技术也逐渐成为了研究的热点之一。其中&#xff0c;ChatGPT作为一项领先的自然语言处理技术…

【软件测试】基础知识第一篇

文章目录一. 什么是软件测试二. 测试和调试的区别三. 什么是测试用例四. 软件的生命周期五. 软件测试的生命周期一. 什么是软件测试 软件测试就是验证软件产品特性是否满足用户的需求。 那需求又是什么呢&#xff1f;在多数软件公司&#xff0c;会有两种需求&#xff0c;一种…

【vue3】小小入门介绍

⭐【前言】 首先&#xff0c;恭喜你打开了一个系统化的学习专栏&#xff0c;在这个vue专栏中&#xff0c;大家可以根据博主发布文章的时间顺序进行一个学习。博主vue专栏指南在这&#xff1a;vue专栏的学习指南 &#x1f973;博主&#xff1a;初映CY的前说(前端领域) &#x1f…

python自动发送邮件,qq邮箱、网易邮箱自动发送和回复

在python中&#xff0c;我们可以用程序来实现向别人的邮箱自动发送一封邮件&#xff0c;甚至可以定时&#xff0c;如每天8点钟准时给某人发送一封邮件。今天&#xff0c;我们就来学习一下&#xff0c;如何向qq邮箱&#xff0c;网易邮箱等发送邮件。 一、获取邮箱的SMTP授权码。…

new动态内库管理库学习

new文件是动态内存管理库的一部分&#xff0c;特别提供低层内存管理特性。 它包括bad_alloc, bad_array_new_length&#xff0c;nothrow_t&#xff0c;align_val_t类nothrow常量&#xff0c;以及函数 operator newoperator new[],operator deleteoperator delete[],get_new_han…

微信小程序登录注册页面

// login.js // 获取应用实例 var app getApp() var api require("../../utils/api.js")Page({data: {motto: zhenbei V1.0.0,userInfo: {},hasUserInfo: false,disabled: true,btnstate: default,username: ,password: ,canIUse: wx.canIUse(button.open-type.get…

Python实现人脸识别检测, 对美女主播照片进行评分排名

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 素材、视频、代码、插件安装教程我都准备好了&#xff0c;直接在文末名片自取就可点击此处跳转 开发环境: Python 3.8 Pycharm 2021.2 模块使用&#xff1a; requests >>> pip install requests tqdm >…

如何利用WDM波分复用技术来扩展光纤容量?

文章导读&#xff1a; 如何利用WDM来扩展光纤容量&#xff1f; 什么是Mux合波和Demux分波&#xff1f; CWDM, DWDM, OADM 了解WDM的常用波段 WDM技术&#xff1a;TFF和AWG WDM-PON应用于接入网 WDM网络拓扑在5G传输中的应用 网络提供商一直面临着如何应对不断扩大的带宽需求&a…

【Pytorch】利用PyTorch实现图像识别

本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 这是目录使用torchvision库的datasets类加载常用的数据集或自定义数据集使用torchvision库进行数据增强和变换&#xff0c;自定义自己的图像分类数据集并使用torchvision库加载它们使…

3月最新!AIGC公司生态地图;开发者实用ChatGPT工具清单;上手必会的SD绘图教程;字幕组全自动化流程大公开 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『光年之外诚邀产品经理加入』古典产品经理的复兴&#xff01; 光年之外创始人王慧文在社交平台发帖&#xff0c;公布联合创始人团队基…

【C语言初阶】循环语句

文章目录&#x1f490;专栏导读&#x1f490;文章导读&#x1f337;什么是循环&#x1f337;while循环&#x1f337;do while循环&#x1f337;for循环&#x1f337;循环结构中的break与continue&#x1f33a;break&#x1f33a;continue&#x1f337;goto语句&#x1f490;专栏…

5G将在五方面彻底改变制造业

想象一下这样一个未来&#xff0c;智能机器人通过在工厂车间重新配置自己&#xff0c;从多条生产线上组装产品。安全无人机处理着从监视入侵者到确认员工停车等繁琐的任务。自动驾驶汽车不仅可以在建筑物之间运输零部件&#xff0c;还可以在全国各地运输。工厂检查可以在千里之…

java基于SSH框架的超市管理系统mvc

目 录 1、引言 4 1.1 研究现状 4 1.2 主要研究的目的及内容 5 1.3 研究方法及设计思路 5 1.3.1 研究方法 5 1.3.2 设计思路 6 2、应用需求分析与可行性分析 6 2.1 应用需求分析 7 2.2 运行需求分析 8 2.3 其他需求分析 8 2.4 可行性分析 8 2.…

SpringBoot实战(十三)集成 Admin

目录一、简介二、搭建 springboot-admin 管理服务1.Maven 依赖2.application.yml3.添加 EnableAdminServer4.启动服务&#xff0c;查看页面三、搭建 springboot-admin-client 客户端服务1.Maven 依赖2.application.yml3.启动服务&#xff0c;查看页面四、搭配 Eureka 使用1.搭建…

二叉树的顺序存储与手撕数据结构—堆

TIPS树的话是一种非线性的数据结构&#xff0c;他实际上就是具有一定层次关系的数据集合&#xff0c;并且在树形结构当中&#xff0c;子树之间不能有任何的交集&#xff0c;否则就不是树形结构。然后对于树而言的话&#xff0c;在实际应用当中并不是特别多&#xff0c;在实际应…

Linux防火墙——SNAT、DNAT

目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条件 1、临时打开 2、永久打开 3、SNAT转换1&#xff1a;固定的公网IP地址 4、SNAT转换2&#xff1a;非固定的公网IP地址&#xff08;共享动态IP地址&#xff09; 二、SNAT实验 配置web服务…