WEEK19:django 博客开发2
- 路由系统 URL
a标签中的的链接在新标签页面打开则需要添加“target=_blank”
- 一个url对应一个网页(静态)
函数:url(r"index/",views.index)
类:url(r"home/",views.Home.as_view()) - 一个url对应一类网页(动态)
- 严格按照形式参数顺序
url(r"detail-(\d+).html",views.detail)
url(r'^detail-(\d+)-(\d+).html', views.detail), def func(request, nid, uid): #nid和pid的顺序必须先nid=2再pid=9 pass def func(request, *args): args = (2,9) def func(request, *args, **kwargs): #**kwargs为空 args = (2,9)
- 在正则表达式中指定形式参数
url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail) #正则表达式的分组,第一个值为nid,第二个值为uid
url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail) def func(request, nid, uid): #nid和uid的顺序随意 pass def funct(request, **kwargs): kwargs = {'nid': 1, 'uid': 3} def func(request, *args, **kwargs): #**kwargs为空 args = (2,9)
- 严格按照形式参数顺序
- name参数(urls.py)
对URL路由关系进行命名, 以后可以根据此名称生成自己想要的URL
#urls.py url(r'^asdfasdfasdf/', views.index, name='i1'), url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'), url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'), #view.py def func(request, *args, **kwargs): from django.urls import reverse url1 = reverse('i1') # asdfasdfasdf/ url2 = reverse('i2', args=(1,2,)) # yug/1/2/ url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/ #xxx.html中的form标签中的action值为 {% url "i1" %} # asdfasdfasdf/ {% url "i2" 1 2 %} # yug/1/2/ {% url "i3" pid=1 nid=9 %} # buy/1/9/ 注: # 当前的URL request.path_info 当前页提交数据 action="{{ request.path_info }}"
- 多级路由
通过include进行路由分发
project/urls.py from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^cmdb/', include("app01.urls")), url(r'^monitor/', include("app02.urls")), ] app01/urls.py from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^login/', views.login), ] app02/urls.py from django.conf.urls import url,include from app02 import views urlpatterns = [ url(r'^login/', views.login), ]
- 一个url对应一个网页(静态)
- 视图
- GET方法一般用来获取数据,POST方法一般用来提交数据
- html中的input标签中的radio\checkbox\select需要一次性提交多个值的时候,在views.py中使用request.POST.getlist('xxx')获取
- 上传文件需要在form标签中添加“ enctype="multipart/form-data" ”
上传的文件在views.py中使用obj=request.FILES.get('xxx')获取
获取文件名称使用obj.name
写文件到服务端使用
file_path=os.path.join(upload,obj.name)
f=open(file_path,mode="wb") for i in obj.chunks(): f.write(i) f.close() - FBV & CBV
- FBV
url.py
'home/' views.home
views.py
def home(request):
...... - CBV
url.py
'index/' views.Home.as_vies()
views.py
import django.views import View #继承类
class Home(View):
#可定义的方法:get,post,put,patch,delete,head,options,trace(点击View,跳转到base.py,查看详细的方法介绍)
def get(self,request): #处理get请求,函数的写法和FBV一样
......
def post(self,request): #处理post请求
......
- FBV
- 模板
- ORM操作
select * from tb where id > 1
# 对应关系
models.tb.objects.filter(id__gt=1)
models.tb.objects.filter(id=1)
models.tb.objects.filter(id__lt=1)- 创建类
- 先写类
from django.db import models # app01_userinfo class UserInfo(models.Model): # id列,自增,主键 # 用户名列,字符串类型,指定长度 username = models.CharField(max_length=32) password = models.CharField(max_length=64)
- 注册APP
project/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', #添加APP ]
- 执行命令
python manage.py makemigrations #生成数据库临时文件APP/migrations/xxxx_initial.py python manage.py migrate #根据临时文件生成数据库
- ********** 使用mysql注意 ***********
Django默认使用MySQLdb模块链接MySQL 主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可: import pymysql pymysql.install_as_MySQLdb()
- 先写类
- 数据库
- 字段类型
- 基本结构
from django.db import models class userinfo(models.Model): name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField()
- 字段
- AutoField(Field)
int自增列,必须填入参数 primary_key=True - BigAutoField(AutoField)
bigint自增列,必须填入参数 primary_key=True
#注:当model中如果没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32)
- SmallIntegerField(IntegerField)
小整数 -32768 ~ 32767 - PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
正小整数 0 ~ 32767 - IntegerField(Field)
整数列(有符号的) -2147483648 ~ 2147483647 - PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
正整数 0 ~ 2147483647 - BigIntegerField(IntegerField)
长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 - 自定义无符号整数字段
class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED' PS: 返回值为字段在数据库中的属性,Django字段默认的值为: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)',
- BooleanField(Field)
布尔值类型 - NullBooleanField(Field)
可以为空的布尔值 - CharField(Field)
字符类型,必须提供max_length参数, max_length表示字符长度 - TextField(Field)
文本类型 - EmailField(CharField)
字符串类型,Django Admin以及ModelForm中提供验证机制 - GenericIPAddressField(Field)
字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
- 参数
- URLField(CharField)
字符串类型,Django Admin以及ModelForm中提供验证 URL - SlugField(CharField)
字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) - CommaSeparatedIntegerField(CharField)
字符串类型,格式必须为逗号分割的数字 - UUIDField(Field)
字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 - FilePathField(Field)
字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数
path:文件夹路径
match=None:正则匹配
recursive=False:递归下面的文件夹
allow_files=True:允许文件
allow_folders=False:允许文件夹
- 参数
- FileField(Field)
字符串,路径保存在数据库,文件上传到指定目录
- 参数
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
- 参数
- ImageField(FileField)
字符串,路径保存在数据库,文件上传到指定目录
- 参数
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
- 参数
- DateTimeField(DateField)
日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] - DateField(DateTimeCheckMixin, Field)
日期格式 YYYY-MM-DD - TimeField(DateTimeCheckMixin, Field)
时间格式 HH:MM[:ss[.uuuuuu]] - DurationField(Field)
长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 - FloatField(Field)
浮点型 - DecimalField(Field)
10进制小数
- 参数
max_digits,小数总长度
decimal_places,小数位长度
- 参数
- BinaryField(Field)
二进制类型
- AutoField(Field)
- 参数
- null
数据库中字段是否可以为空 - default
数据库中字段的默认值 - primary_key
数据库中字段是否为主键 - db_index
数据库中字段是否可以建立索引 - unique
数据库中字段是否可以建立唯一索引 - unique_for_date
数据库中字段【日期】部分是否可以建立唯一索引 - unique_for_month
数据库中字段【月】部分是否可以建立唯一索引 - unique_for_year
数据库中字段【年】部分是否可以建立唯一索引 - auto_now
创建时,自动生成时间 - auto_now_add
更新时,自动更新为当前时间
#下面情况不更新时间 # obj = UserGroup.objects.filter(id=1).update(caption='CEO') #下面情况更新时间 # obj = UserGroup.objects.filter(id=1).first() # obj.caption = "CEO" # obj.save()
- db_column
数据库中字段的列名 - db_tablespace
索引名 - choices
Django admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) - blank
Django admin中是否允许用户输入为空 - verbose_name
Django admin中显示的字段名称中文 - editable
Django admin中是否可以编辑 - help_text
Django admin中该字段的提示信息 - error_messages
Django admin自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'} - validators
Django form 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\ MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ 'c1': '优先错信息1', 'c2': '优先错信息2', 'c3': '优先错信息3', }, validators=[ RegexValidator(regex='root_\d+', message='错误了', code='c1'), RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'), EmailValidator(message='又错误了', code='c3'), ] )
- null
- 元信息
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # 联合索引 index_together = [ ("pub_date", "deadline"), ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # admin中显示的表名称 verbose_name # verbose_name加s verbose_name_plural
- 连表结构
- 一对多:models.ForeignKey(其他表)
当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。 - 多对多:models.ManyToManyField(其他表)
在某表中创建一行数据时,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好 - 一对一:models.OneToOneField(其他表)
在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据 - 字段以及参数
- ForeignKey(ForeignObject) # ForeignObject(RelatedField)
- to # 要进行关联的表名
- to_field=None # 要关联的表中的字段名称
- on_delete=None # 当删除关联表中的数据时,当前表与其关联的行的行为
- models.CASCADE,删除关联数据,与之关联也删除
- models.DO_NOTHING,删除关联数据,引发错误IntegrityError
- models.PROTECT,删除关联数据,引发错误ProtectedError
- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
- models.SET,删除关联数据
- 与之关联的值设置为指定值,设置:models.SET(值)
- 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id" on_delete=models.SET(func),)
- related_name=None # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
- related_query_name=None # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
- limit_choices_to=None # 在Admin或ModelForm中显示关联数据时,提供的条件:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q - limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
- db_constraint=True # 是否在数据库中创建外键约束
- parent_link=False # 在Admin中是否显示关联数据
- OneToOneField(ForeignKey)
- to # 要进行关联的表名
- to_field=None # 要关联的表中的字段名称
- on_delete=None # 当删除关联表中的数据时,当前表与其关联的行的行为
# 对于一对一 # 1. 一对一其实就是 一对多 + 唯一索引 # 2.当两个类之间有继承关系时,默认会创建一个一对一字段 # 如下会在A表中额外增加一个c_ptr_id列且唯一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1)
- ManyToManyField(RelatedField)
- to # 要进行关联的表名
- related_name=None # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
- related_query_name=None # 反向操作时,使用的连接前缀,用于替换【表名】 , 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
- limit_choices_to=None # 在Admin或ModelForm中显示关联数据时,提供的条件:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q - limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
- symmetrical=None # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段 models.BB.objects.filter(...) # 可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False)
- through=None # 自定义第三张表时,使用字段用于指定关系表
- through_fields=None # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64)
- db_constraint=True # 是否在数据库中创建外键约束
- db_table=None # 默认创建第三张表时,数据库中表的名称
- ForeignKey(ForeignObject) # ForeignObject(RelatedField)
- 一对多:models.ForeignKey(其他表)
- 基本结构
- 基本的增删改查
from app01 import models #需要引入APP的models.py,主要使用其中的函数UserInfo(定义变量类型) def orm(request): # 创建 ###方法一: models.UserInfo.objects.create(username='root',password='123') ###方法二: dic = {'username': 'eric', 'password': '666'} models.UserInfo.objects.create(**dic) ###方法三: obj = models.UserInfo(username='alex',password='123') obj.save() # 查 ###查找所有结果 result = models.UserInfo.objects.all() #查询结果: # result,QuerySet => Django => []列表,userinfo的对象 # [obj(id,username,password),obj(id,username,password), obj(id,username,password)] for row in result: print(row.id,row.username,row.password) print(result) ###查询单条记录 result = models.UserInfo.objects.filter(username='root',password='123') #and条件 print(result)
#获取到的一个对象,如果不存在就报错(不建议使用,使用filter(id=1).first())
models.UserInfo.objects.get(id=1)
# QuerySet,返回的元素为对象
models.UserInfo.objects.filter(id=1,name='root')
models.UserInfo.objects.filter(id__gt=1,name='root')
models.UserInfo.objects.filter(id__lt=1)
models.UserInfo.objects.filter(id__gte=1)
models.UserInfo.objects.filter(id__lte=1)
models.UserInfo.objects.filter(id=1,name='root')
dic = {'name': 'xx', 'age__gt': 19}
models.UserInfo.objects.filter(**dic)
v1 = models.Business.objects.all()
# QuerySet,返回的元素为字典
v2 = models.Business.objects.all().values('id','caption')
# QuerySet,返回的元素为元组(列表)
v3 = models.Business.objects.all().values_list('id','caption')
# 跨表查询
#方法一:使用.
v = models.Host.objects.filter(nid__gt=0)
v[0].b.caption ----> 通过符号“.”进行跨表
#方法二:使用__
models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption') # 删除 models.UserInfo.objects.filter(username="alex").delete() # 更新 models.UserInfo.objects.filter(id=3).update(password="69")
# dic = {'name': 'xx', 'age': 19}
# models.UserInfo.objects.filter(id__gt=1).update(**dic)
return HttpResponse('orm') - 应用:用户登录、用户信息查看、用户信息编辑等
- app01/models.py
from django.db import models # Create your models here. # app01_userinfo数据库表名 class UserInfo(models.Model): #必须继承models.Model # id列,自增,主键 # 用户名列,字符串类型,指定长度 username = models.CharField(max_length=32) password = models.CharField(max_length=64)
- app01/urls.py
from app01 import views urlpatterns = [ url(r'^login/', views.login), url(r'^index/', views.index), url(r'^user_info/', views.user_info), url(r'^userdetail-(?P<nid>\d+)/', views.user_detail), url(r'^userdel-(?P<nid>\d+)/', views.user_del), url(r'^useredit-(?P<nid>\d+)/', views.user_edit), url(r'^orm/', views.orm), ]
- urls.py
urlpatterns = [ url(r'^cmdb/', include("app01.urls")), url(r'^monitor/', include("app02.urls")), ]
- views.py
from django.shortcuts import render,HttpResponse,redirect def login(request): if request.method == "GET": return render(request, 'login.html') elif request.method == "POST": # 数据库中执行 select * from user where usernam='x' and password='x' u = request.POST.get('user') p = request.POST.get('pwd') ##判断能否登陆的方法 # 方法一:获取的第一个列表值是否为空(常用,能够保存查询到的信息) # obj = models.UserInfo.objects.filter(username=u,password=p).first() # 方法二:列表的长度是否为0 # count = models.UserInfo.objects.filter(username=u, password=p).count() obj = models.UserInfo.objects.filter(username=u, password=p).first() if obj: return redirect('/cmdb/index/') else: return render(request, 'login.html') else: return redirect('/index/') def index(request): return render(request, 'index.html') def user_info(request): if request.method == "GET": user_list = models.UserInfo.objects.all() return render(request, 'user_info.html', {'user_list': user_list}) elif request.method == 'POST': u = request.POST.get('user') p = request.POST.get('pwd') models.UserInfo.objects.create(username=u,password=p) return redirect('/cmdb/user_info/') def user_detail(request, nid): obj = models.UserInfo.objects.filter(id=nid).first() # 取单条数据,如果不存在,直接报错 # models.UserInfo.objects.get(id=nid) return render(request, 'user_detail.html', {'obj': obj}) def user_del(request, nid): models.UserInfo.objects.filter(id=nid).delete() return redirect('/cmdb/user_info/') def user_edit(request, nid): if request.method == "GET": obj = models.UserInfo.objects.filter(id=nid).first() return render(request, 'user_edit.html',{'obj': obj}) elif request.method == "POST": nid = request.POST.get('id') u = request.POST.get('username') p = request.POST.get('password') models.UserInfo.objects.filter(id=nid).update(username=u,password=p) return redirect('/cmdb/user_info/')
- index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; } .menu{ display: block; padding: 5px; } </style> </head> <body> <div> <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: brown;"> <a class="menu" href="/cmdb/user_info/">用户管理</a> <a class="menu" href="/cmdb/user_group/">用户组管理</a> </div> </div> </body> </html>
- login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/cmdb/login/" method="POST" enctype="multipart/form-data"> <p> <input type="text" name="user" placeholder="用户名" /> </p> <p> <input type="password" name="pwd" placeholder="密码" /> </p> <input type="submit" value="提交"/> </form> </body> </html>
- user_info.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; } .menu{ display: block; padding: 5px; } </style> </head> <body> <div> <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: brown;"> <a class="menu" href="/cmdb/user_info/">用户管理</a> <a class="menu" href="/cmdb/user_group/">用户组管理</a> </div> <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto"> <h3>添加用户</h3> <form method="POST" action="/cmdb/user_info/"> <input type="text" name="user" /> <input type="text" name="pwd" /> <input type="submit" value="添加"/> </form> <h3>用户列表</h3> <ul> {% for row in user_list %} <li> <a href="/cmdb/userdetail-{{ row.id }}/">{{ row.username }}</a> | <a href="/cmdb/userdel-{{ row.id }}/">删除</a> | <a href="/cmdb/useredit-{{ row.id }}/">编辑</a> </li> {% endfor %} </ul> </div> </div> </body> </html>
- user_edit.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; } .menu{ display: block; padding: 5px; } </style> </head> <body> <div> <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: brown;"> <a class="menu" href="/cmdb/user_info/">用户管理</a> <a class="menu" href="/cmdb/user_group/">用户组管理</a> </div> <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto"> <h1>编辑用户</h1> <form method="post" action="/cmdb/useredit-{{ obj.id }}/"> <input style="display: none" type="text" name="id" value="{{ obj.id }}" /> <input type="text" name="username" value="{{ obj.username }}" /> <input type="text" name="password" value="{{ obj.password }}"/> <input type="submit" value="提交" /> </form> </div> </div> </body> </html>
- user_detail.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; } .menu{ display: block; padding: 5px; } </style> </head> <body> <div> <div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: brown;"> <a class="menu" href="/cmdb/user_info/">用户管理</a> <a class="menu" href="/cmdb/user_group/">用户组管理</a> </div> <div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto"> <h1>用户详细信息</h1> <h5>{{ obj.id }}</h5> <h5>{{ obj.name }}</h5> <h5>{{ obj.password }}</h5> </div> </div> </body> </html>
- app01/models.py
- 字段类型
- 创建类
仰天大笑出门去,吾辈岂是蓬蒿人!