1、准备环境

django-admin startproject 项目名称 # 创建django项目
python manage.py startapp app名 # 创建app

setting.py 的时区语言、数据库、app配置

DEBUG = True

INSTALLED_APPS = [
    'django.contrib.admin', # 后台管理系统
    'django.contrib.auth', # 用户认证模块
    'django.contrib.contenttypes', # 内容类型处理
    'django.contrib.sessions', # 会话管理
    'django.contrib.messages', # 消息管理
    'django.contrib.staticfiles', # 静态文件管理
    'General' # 创建的app
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': 3306
    }
}

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_TZ = True

DEBUG = True才可以访问admin

urls.py里面可以修改站点访问路径,默认是admin,那么python manage.py runserver 127.0.0.1:8080就是访问http://127.0.0.1:8080/admin/

urlpatterns = [
    path('admin/', admin.site.urls), # 可修改url
]

2、新建APP、修改models.py

这是一个示例用的models.py

from typing import Any
from django.db import models
import datetime
# Create your models here.

# models.Manager模型管理类
class QuestionManager(models.Manager):
    def get(self, *args: Any, **kwargs: Any) -> Any: # 重写get方法
        try:
            return super().get(*args, **kwargs)
        except:
            return None
        
    def get_tags(self, name) -> models.QuerySet: # 自定义方法
        question = super.get(name=name)
        if question:
            return question.tag.all()
        else:
            return []

class Question(models.Model):
    id = models.AutoField(primary_key=True)
    no = models.IntegerField(null=False,unique=True,verbose_name='题号')
    name = models.CharField('题目',blank=False,max_length=1024)
    href = models.URLField('链接')
    class_name = models.CharField('类名',blank=False,unique=True,max_length=128)
    update_time = models.DateTimeField('修改时间',auto_now=True)

    objects = models.Manager() # 使objects不被QuestionManager覆盖
    question_manager = QuestionManager() # 添加自定义模型 它会覆盖objects,如果不行被覆盖,就加上objects = models.Manager()
    
    class Meta:
        db_table = 'question'
        verbose_name = '问题'
        verbose_name_plural = '问题'
    
    def update(cls,*args,**kwargs):
        super().update(*args,**kwargs,updated_at=datetime.dattime.now())
    
    @property
    def tags(self):  # 将方法转换为属性
        res = []
        for t in self.tag.all(): # 通过外键反向查找
            res.append(t.name)
        return ' '.join(res)
    
    def __str__(self) -> str:
        return self.name


tag_choices = (
    ('排序','排序'),
    ('回溯法','回溯法'),
    ('动态规划','动态规划'),
    ('二叉树','二叉树'),
)
class Tag(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField('标签名',choices=tag_choices,blank=False,max_length=128)
    question = models.ForeignKey(Question,related_name='tag',null=True,on_delete=models.SET_NULL,verbose_name='问题')
    class Meta:
        db_table = 'tag'
        verbose_name = '标签'
        verbose_name_plural = '标签'
        unique_together = ['name', 'question']


class Test(models.Model):
    id = models.AutoField(primary_key=True)
    update_time = models.DateTimeField(auto_now=True)
    result = models.IntegerField(choices=((0,'失败'),(1,'成功')),default=1)
    question = models.ForeignKey(Question, related_name='test',null=True,on_delete=models.SET_NULL,verbose_name='问题')
    class Meta:
        db_table = 'test'
        verbose_name = '测试'
        verbose_name_plural = '测试'

2.1、models.Manager

models.Manager:可以自定义模型管理对象,重写all、filter、get,也可以自定义方法

上面的例子中QuestionManager是自定义模型类,在Question中使用

Manager会自动覆盖objects,如果不想objects被覆盖,就需要加上objects = models.Manager()

下面是验证效果

try:
    question = Question.objects.get(name='123') # 报错
    print("Question.objects.get(name='123')",question)
except:
    print("Question.objects.get(name='123') raise error")

try:
    question = Question.question_manager.get(name='123') # 返回None
    print("Question.question_manager.get(name='123')",question)
except:
    print("Question.question_manager.get(name='123') raise error")

2.2、@property

@property:将方法转换为属性

使用方法:

question = Question.objects.get(name='aaa')
print(question.tags)

2.3、verbose_name

verbose_name是admin中对应的名称

2.4、执行迁移

python manage.py makemigrations
python manage.py migrate

3、将models加入admin

在app的下面有一个admin.py文件

from django.contrib import admin

# Register your models here.
from django.contrib import admin
from General.models import Question,Tag,Test

# 可以修改admin的title及header
admin.site.site_header = 'XX平台'
admin.site.site_title = 'XX系统'

class QuestionAdmin(admin.ModelAdmin):
    # tags是@property装饰的方法,数据库不包含这个字段,只用来展示数据
    # 我么也可以自定义方法来展示数据,如get_tags
    list_display = ('no', 'name', 'tags', 'href','update_time', 'get_question_tags') # 列表中展示
    list_editable = ('href',) # 列表中编辑
    list_filter = ('name',) # 列表中过滤
    list_display_links = ('name',) # 在字段上创建链接,点进去进入编辑页面
    list_max_show_all = 10 # 列表中最多展示数据
    list_per_page = 10 # 用于分页 每页最多展示数据
    ordering = ['no'] # 排序
    fields = (('no', 'name'), ('class_name', 'href')) # 编辑页面的数据展示

    # 数据库中不存在,仅用于admin中展示数据
    def get_question_tags(self,obj):
        res = [t.name for t in obj.tag.all()]
        return ', '.join(res)
    get_question_tags.short_description = '标签' # 定义字段名

    # 另外一种写法 使用装饰器 效果相同
    # @admin.display(description='标签')
    # def get_question_tags(self,obj):
    #     res = [t.name for t in obj.tag.all()]
    #     return ', '.join(res)

admin.site.register(Question, QuestionAdmin)
admin.site.register(Tag)
admin.site.register(Test)

如果有只想在admin中展示,表中不存在的数据,可以参考get_question_tags的写法

效果如下:

tag和test没有admin.ModelAdmin注入,效果如下

有一点要注意,外键是不能直接展示在list_display中的,如果想要展示需要类似get_question_tags的处理

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐