您的位置:首页 > 财经 > 金融 > 天津疫情防控最新动态_seo是什么职业做什么的_一份完整的营销策划方案_广告营销推广

天津疫情防控最新动态_seo是什么职业做什么的_一份完整的营销策划方案_广告营销推广

2025/1/11 6:46:12 来源:https://blog.csdn.net/weixin_40780178/article/details/145022559  浏览:    关键词:天津疫情防控最新动态_seo是什么职业做什么的_一份完整的营销策划方案_广告营销推广
天津疫情防控最新动态_seo是什么职业做什么的_一份完整的营销策划方案_广告营销推广

Django 实操图书管理系统

一、学习目标

今天是Django框架学习的最后一天,我们将通过实现一个完整的图书管理系统来综合运用之前学习的知识。本项目将包含:

  1. 设计并实现图书相关模型
  2. 使用GraphQL构建API接口
  3. 开发前端页面并与后端集成

二、系统架构

2.1 技术栈选型

层级技术选择说明
后端Django 4.2Web框架
APIGraphene-Django 3.0GraphQL实现
ORMDjango ORM数据库操作
前端React 18用户界面
状态管理Apollo ClientGraphQL客户端
UI库Ant Design组件库
数据库PostgreSQL关系型数据库

2.2 系统架构图

三、后端实现

3.1 数据模型设计

首先创建必要的模型:

# books/models.py
from django.db import models
from django.contrib.auth.models import Userclass Author(models.Model):name = models.CharField(max_length=100)biography = models.TextField(blank=True)created_at = models.DateTimeField(auto_now_add=True)def __str__(self):return self.nameclass Category(models.Model):name = models.CharField(max_length=50)description = models.TextField(blank=True)class Meta:verbose_name_plural = "categories"def __str__(self):return self.nameclass Book(models.Model):title = models.CharField(max_length=200)isbn = models.CharField(max_length=13, unique=True)description = models.TextField()author = models.ForeignKey(Author, on_delete=models.CASCADE)category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)publication_date = models.DateField()price = models.DecimalField(max_digits=10, decimal_places=2)stock = models.IntegerField(default=0)cover_image = models.ImageField(upload_to='book_covers/', null=True, blank=True)created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)def __str__(self):return self.titleclass BookLoan(models.Model):LOAN_STATUS = (('BORROWED', 'Borrowed'),('RETURNED', 'Returned'),('OVERDUE', 'Overdue'),)book = models.ForeignKey(Book, on_delete=models.CASCADE)user = models.ForeignKey(User, on_delete=models.CASCADE)borrowed_date = models.DateTimeField(auto_now_add=True)due_date = models.DateTimeField()returned_date = models.DateTimeField(null=True, blank=True)status = models.CharField(max_length=10, choices=LOAN_STATUS, default='BORROWED')def __str__(self):return f"{self.book.title} - {self.user.username}"

3.2 GraphQL Schema实现

# books/schema.py
import graphene
from graphene_django import DjangoObjectType
from .models import Book, Author, Category, BookLoan
from django.contrib.auth.models import Userclass UserType(DjangoObjectType):class Meta:model = Userfields = ('id', 'username', 'email')class AuthorType(DjangoObjectType):class Meta:model = Authorfields = '__all__'class CategoryType(DjangoObjectType):class Meta:model = Categoryfields = '__all__'class BookType(DjangoObjectType):class Meta:model = Bookfields = '__all__'class BookLoanType(DjangoObjectType):class Meta:model = BookLoanfields = '__all__'class Query(graphene.ObjectType):all_books = graphene.List(BookType)book = graphene.Field(BookType, id=graphene.Int())books_by_author = graphene.List(BookType, author_id=graphene.Int())books_by_category = graphene.List(BookType, category_id=graphene.Int())user_loans = graphene.List(BookLoanType, user_id=graphene.Int())def resolve_all_books(self, info):return Book.objects.all()def resolve_book(self, info, id):return Book.objects.get(pk=id)def resolve_books_by_author(self, info, author_id):return Book.objects.filter(author_id=author_id)def resolve_books_by_category(self, info, category_id):return Book.objects.filter(category_id=category_id)def resolve_user_loans(self, info, user_id):return BookLoan.objects.filter(user_id=user_id)class CreateBook(graphene.Mutation):class Arguments:title = graphene.String(required=True)isbn = graphene.String(required=True)description = graphene.String()author_id = graphene.Int(required=True)category_id = graphene.Int()publication_date = graphene.Date(required=True)price = graphene.Decimal(required=True)stock = graphene.Int(required=True)book = graphene.Field(BookType)def mutate(self, info, **kwargs):book = Book.objects.create(**kwargs)return CreateBook(book=book)class CreateBookLoan(graphene.Mutation):class Arguments:book_id = graphene.Int(required=True)user_id = graphene.Int(required=True)due_date = graphene.DateTime(required=True)book_loan = graphene.Field(BookLoanType)def mutate(self, info, book_id, user_id, due_date):book = Book.objects.get(pk=book_id)user = User.objects.get(pk=user_id)if book.stock <= 0:raise graphene.GraphQLError("Book is out of stock")book_loan = BookLoan.objects.create(book=book,user=user,due_date=due_date)book.stock -= 1book.save()return CreateBookLoan(book_loan=book_loan)class ReturnBook(graphene.Mutation):class Arguments:loan_id = graphene.Int(required=True)book_loan = graphene.Field(BookLoanType)def mutate(self, info, loan_id):from django.utils import timezonebook_loan = BookLoan.objects.get(pk=loan_id)book_loan.returned_date = timezone.now()book_loan.status = 'RETURNED'book_loan.save()book = book_loan.bookbook.stock += 1book.save()return ReturnBook(book_loan=book_loan)class Mutation(graphene.ObjectType):create_book = CreateBook.Field()create_book_loan = CreateBookLoan.Field()return_book = ReturnBook.Field()schema = graphene.Schema(query=Query, mutation=Mutation)

3.3 URL配置

# library_project/urls.py
from django.contrib import admin
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLViewurlpatterns = [path('admin/', admin.site.urls),path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))),
]

四、前端实现

4.1 Apollo Client配置

// src/apollo.js
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';const httpLink = createHttpLink({uri: 'http://localhost:8000/graphql/',
});const client = new ApolloClient({link: httpLink,cache: new InMemoryCache()
});export default client;

4.2 图书列表组件

// src/components/BookList.js
import React from 'react';
import { useQuery, gql } from '@apollo/client';
import { Table, Tag, Space } from 'antd';const GET_BOOKS = gql`query GetBooks {allBooks {idtitleisbnauthor {name}category {name}pricestock}}
`;const BookList = () => {const { loading, error, data } = useQuery(GET_BOOKS);const columns = [{title: 'Title',dataIndex: 'title',key: 'title',},{title: 'Author',dataIndex: ['author', 'name'],key: 'author',},{title: 'Category',dataIndex: ['category', 'name'],key: 'category',},{title: 'Price',dataIndex: 'price',key: 'price',render: (price) => `$${price}`,},{title: 'Stock',dataIndex: 'stock',key: 'stock',render: (stock) => (<Tag color={stock > 0 ? 'green' : 'red'}>{stock > 0 ? 'In Stock' : 'Out of Stock'}</Tag>),},];if (loading) return <p>Loading...</p>;if (error) return <p>Error :(</p>;return (<Table columns={columns} dataSource={data.allBooks} rowKey="id"/>);
};export default BookList;

4.3 借书表单组件

// src/components/LoanBookForm.js
import React from 'react';
import { Form, Input, DatePicker, Button, message } from 'antd';
import { useMutation, gql } from '@apollo/client';const CREATE_LOAN = gql`mutation CreateBookLoan($bookId: Int!, $userId: Int!, $dueDate: DateTime!) {createBookLoan(bookId: $bookId, userId: $userId, dueDate: $dueDate) {bookLoan {idborrowedDatedueDatestatus}}}
`;const LoanBookForm = ({ bookId }) => {const [createLoan] = useMutation(CREATE_LOAN);const [form] = Form.useForm();const onFinish = async (values) => {try {const { data } = await createLoan({variables: {bookId: bookId,userId: values.userId,dueDate: values.dueDate.toISOString(),},});message.success('Book loan created successfully!');form.resetFields();} catch (error) {message.error('Failed to create book loan');}};return (<Formform={form}layout="vertical"onFinish={onFinish}><Form.Itemname="userId"label="User ID"rules={[{ required: true, message: 'Please input user ID!' }]}><Input type="number" /></Form.Item><Form.Itemname="dueDate"label="Due Date"rules={[{ required: true, message: 'Please select due date!' }]}><DatePicker showTime /></Form.Item><Form.Item><Button type="primary" htmlType="submit">Create Loan</Button></Form.Item></Form>);
};export default LoanBookForm;

五、系统流程图

在这里插入图片描述

六、关键功能实现细节

6.1 图书库存管理

# books/services.py
from django.db import transaction
from django.core.exceptions import ValidationError
from .models import Book, BookLoanclass BookInventoryService:@staticmethod@transaction.atomicdef check_out_book(book_id, user_id, due_date):"""处理图书借出业务逻辑"""try:book = Book.objects.select_for_update().get(pk=book_id)if book.stock <= 0:raise ValidationError("Book is not available for checkout")book_loan = BookLoan.objects.create(book_id=book_id,user_id=user_id,due_date=due_date)book.stock -= 1book.save()return book_loanexcept Book.DoesNotExist:raise ValidationError("Book not found")@staticmethod@transaction.atomicdef return_book(loan_id):"""处理图书归还业务逻辑"""try:loan = BookLoan.objects.select_related('book').get(pk=loan_id)if loan.status == 'RETURNED':raise ValidationError("Book already returned")loan.mark_as_returned()book = loan.bookbook.stock += 1book.save()return loanexcept BookLoan.DoesNotExist:raise ValidationError("Loan record not found")

6.2 图书搜索功能

# books/schema.pyclass Query(graphene.ObjectType):# ... 其他查询search_books = graphene.List(BookType,search_term=graphene.String(required=True),category_id=graphene.Int(),min_price=graphene.Float(),max_price=graphene.Float(),)def resolve_search_books(self, info, search_term, category_id=None, min_price=None, max_price=None):queryset = Book.objects.all()# 基本搜索queryset = queryset.filter(Q(title__icontains=search_term) |Q(description__icontains=search_term) |Q(author__name__icontains=search_term))# 分类过滤if category_id:queryset = queryset.filter(category_id=category_id)# 价格范围过滤if min_price is not None:queryset = queryset.filter(price__gte=min_price)if max_price is not None:queryset = queryset.filter(price__lte=max_price)return queryset

6.3 前端搜索组件

// src/components/BookSearch.js
import React, { useState } from 'react';
import { Input, Select, Form, Button, Card, List } from 'antd';
import { useQuery, gql } from '@apollo/client';const { Option } = Select;const SEARCH_BOOKS = gql`query SearchBooks($searchTerm: String!, $categoryId: Int, $minPrice: Float, $maxPrice: Float) {searchBooks(searchTerm: $searchTermcategoryId: $categoryIdminPrice: $minPricemaxPrice: $maxPrice) {idtitleauthor {name}category {name}pricestock}}
`;const GET_CATEGORIES = gql`query GetCategories {allCategories {idname}}
`;const BookSearch = () => {const [searchParams, setSearchParams] = useState({searchTerm: '',categoryId: null,minPrice: null,maxPrice: null});const { data: categoriesData } = useQuery(GET_CATEGORIES);const { loading, error, data } = useQuery(SEARCH_BOOKS, {variables: searchParams,skip: !searchParams.searchTerm});const onFinish = (values) => {setSearchParams({...values,categoryId: values.categoryId ? parseInt(values.categoryId) : null});};return (<div><Formlayout="inline"onFinish={onFinish}style={{ marginBottom: 24 }}><Form.Item name="searchTerm"><Input placeholder="Search books..." /></Form.Item><Form.Item name="categoryId"><Select placeholder="Select category" allowClear style={{ width: 200 }}>{categoriesData?.allCategories.map(category => (<Option key={category.id} value={category.id}>{category.name}</Option>))}</Select></Form.Item><Form.Item name="minPrice"><Input type="number" placeholder="Min price" /></Form.Item><Form.Item name="maxPrice"><Input type="number" placeholder="Max price" /></Form.Item><Form.Item><Button type="primary" htmlType="submit">Search</Button></Form.Item></Form>{loading && <p>Searching...</p>}{error && <p>Error: {error.message}</p>}{data && (<Listgrid={{ gutter: 16, column: 3 }}dataSource={data.searchBooks}renderItem={book => (<List.Item><Card title={book.title}><p>Author: {book.author.name}</p><p>Category: {book.category.name}</p><p>Price: ${book.price}</p><p>Stock: {book.stock}</p></Card></List.Item>)}/>)}</div>);
};export default BookSearch;

6.4 系统配置

# settings.py 相关配置INSTALLED_APPS = [# ...'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','graphene_django','corsheaders','books',
]MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware',# ... 其他中间件
]# GraphQL设置
GRAPHENE = {'SCHEMA': 'books.schema.schema','MIDDLEWARE': ['graphql_jwt.middleware.JSONWebTokenMiddleware',],
}# CORS设置
CORS_ALLOWED_ORIGINS = ["http://localhost:3000",
]# 文件上传设置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')# 数据库设置
DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql','NAME': 'library_db','USER': 'postgres','PASSWORD': 'your_password','HOST': 'localhost','PORT': '5432',}
}

七、部署和运维建议

  1. 数据库优化

    • 为常用查询字段添加索引
    • 配置适当的连接池大小
    • 定期进行数据库维护和备份
  2. 缓存策略

    • 使用Redis缓存热门图书数据
    • 实现图书封面图片的CDN缓存
    • 合理设置缓存失效时间
  3. 性能优化

    • 使用Django的select_related和prefetch_related优化查询
    • 实现分页加载以提高响应速度
    • 合理使用数据库事务确保数据一致性
  4. 安全措施

    • 实现JWT认证
    • 添加请求频率限制
    • 定期更新依赖包
    • 实施SQL注入防护

八、测试用例

# books/tests.py
from django.test import TestCase
from django.contrib.auth.models import User
from django.utils import timezone
from datetime import timedelta
from .models import Book, Author, Category, BookLoan
from .services import BookInventoryServiceclass BookInventoryTests(TestCase):def setUp(self):self.author = Author.objects.create(name="Test Author")self.category = Category.objects.create(name="Test Category")self.user = User.objects.create_user(username="testuser",password="testpass")self.book = Book.objects.create(title="Test Book",isbn="1234567890123",description="Test Description",author=self.author,category=self.category,publication_date=timezone.now().date(),price=29.99,stock=1)def test_successful_checkout(self):due_date = timezone.now() + timedelta(days=14)loan = BookInventoryService.check_out_book(self.book.id,self.user.id,due_date)self.assertEqual(loan.status, "BORROWED")self.book.refresh_from_db()self.assertEqual(self.book.stock, 0)def test_return_book(self):due_date = timezone.now() + timedelta(days=14)loan = BookInventoryService.check_out_book(self.book.id,self.user.id,due_date)returned_loan = BookInventoryService.return_book(loan.id)self.assertEqual(returned_loan.status, "RETURNED")self.book.refresh_from_db()self.assertEqual(self.book.stock, 1)

九、总结

本项目综合运用了Django、GraphQL和React技术栈,实现了一个完整的图书管理系统。通过这个项目,我们实践了:

  1. Django模型设计和关系处理
  2. GraphQL API的构建和查询优化
  3. React前端组件开发和状态管理
  4. 数据库事务和并发控制
  5. 系统测试和性能优化

项目提供了基础的图书管理功能,包括图书信息管理、借阅管理、库存控制等。通过合理的架构设计和代码组织,系统具有良好的可维护性和扩展性。未来可以继续添加更多功能,如读者评论、图书推荐、统计报表等。


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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com