Python 23 Django基础

零、基本配置操作

1、创建Django程序

命令:django-admin startproject name

2、程序目录

3、配置文件

(1)、数据库

1
2
3
4
5
6
7
8
9
10
DATABASES = {
    'default': {
    'ENGINE''django.db.backends.mysql',
    'NAME':'dbname',
    'USER''root',
    'PASSWORD''xxx',
    'HOST': '',
    'PORT': '',
    }
}
1
2
3
4
5
6
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
  
# 如下设置放置的与project同名的配置的 __init__.py文件中
  
import pymysql
pymysql.install_as_MySQLdb() 

(2)、模版

1
2
3
TEMPLATE_DIRS = (
        os.path.join(BASE_DIR,'templates'),
    )

(3)、静态文件

1
2
3
STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )

 

一、url路由系统

1、正则表达式

2、分组和命名分组

re_path(r'xxxx/(\d+)$', xxxx)
re_path(r'xxxx/(?P<name>(\d+))$', xxx)

3、include分发

re_path(r'xxxx/', include('crm.urls'))

4、url别名和namespace

re_path(r'xxxx/', name=xx)
re_path(r'xxxx/', include('crm.urls', 'crm', namespace='crm'))

5、反向解析

# 在视图中
reverse('xx')
reverse('xx', args=(xx, ))
reverse('xx', kwargs(xx=xx, ))
reverse('crm:xx')  # 如果设置了namespace,则需要在前面加crm:

# 在模板中
{% url 'xx' %}
{% url 'xx' 5 %}
{% url 'xx' id=5 %}

 

二、视图

1、FBV和CBV

2、CBV流程

3、request

request.method
request.path_info  # 不包含参数、域名和参数
request.files
request.body

request.is_ajax()

4、response

from django.https import JsonResponse
from django.shortcuts import HttpResponse, render, redirect

HttpResponse("xxx")
render(request, 'xx.html', locals())
redirect('xxx')
JsonResponse({xx:xx})

 

三、模板

模板就是html+Django逻辑语句的组合

1、变量 {{ }}

2、标签(标签是逻辑层面,不能改变数值)

{% for %} #表示遍历循环
{% if %} #表示判断
{% url "name" %} #表示路由地址
{% load %} #加载相关文件
{% csrf_token %} #用于防护跨站请求伪造攻击
{% with %} #重新命名变量名,{% with a as b %} {{ b }} {% endwith %}
{% extends %} #继承模板
{% block %} #重写父类模板的代码

3、过滤器(过滤器可以对数据进行加工)

{{ xx|default: 1 }}  给一个默认值
{{ xx|date: 'Y-m-h' }} 显示时间
{{ xx|safe }} 不再防止xss攻击,不进行转义,也可以将数字类型转化成字符串。

4、自定义simple_tag、filter

1、
在app中创建templatetags文件夹,并创建一个py文件
2、
from django import templates
register = templates.Library()
3、
@register.simple_tag
def xxx(xx):
    return xx
4、
在模板中使用{% load xx %}

5、自定义inclusion_tag

inclusion_tag是用来保存一段html代码,可以直接在模板中套用

使用过程和自定义标签类似。首先在app中创建templatetags文件夹,在其中自定义一个my_html.py文件:

from django import template
register = template.Library()

@register.inclusion_tag('test.html')  # 这里传入参数,表示代码所在的html文件
def test(a):
    return {"xx": xx}

在test.html文件中可以使用传入的xx变量

<div>{{ xx }}</div>

在需要使用的html文件中引用:

{% load my_html %}
{% test request %}

 

四、ORM

1、映射关系

类--表,对象--数据行,属性--字段

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
        
元信息

2、字段类型

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中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    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)
        - 二进制类型
View Code

3、13条查询语句

all()  get()  filter()  exclude()  first()  last()
values()  value_list()
order_by()  reverse()  
distinct()  count()  exist()

4、单表双下划线

__gt  # 大于
__lte  # 小于等于
__in
__range
__is_null
__contains

5、外键查询

6、多对多操作

#有一张作者表,有一张书的表多对多关联了作者表
#为一本书添加一位不存在的作者
book_obj = Books.objects.filter(id=1).first()
book_obj..authors.create(name='xxx')

#为一本书添加几位存在的作者
book_obj.authors.add(author_obj1,author_obj2)
#也可以直接添加id
book_obj.authors.add(1)
#或者用set
book_obj.authors.set([1,2,3])

#为一位作者添加一本不存在的书
author_obj = Authors.objects.filter(id=1).first()
author_obj.books_set.create(name="xx")

#为一位作者添加几本不存在的书
author_obj.books_set.add(book_obj1,book_obj2)
#也可以直接添加id
author_obj.books_set.add(2)

#去除一本书关联的某个作者
book_obj.authors.remove(author_obj)

#清空一本书关联的所有作者
book_obj.authors.clear()
多对多操作
# 第一种:使用ManyToMany字段
# 第二种:自己创建第三张表并通过外键连接,但是无法使用多对多的方法
# 第三种:自己创建第三张表,并通过ManyToMany字段连接

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")

class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
    # through_fields接受一个2元组('field1','field2'):
    # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。


class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")
创建多对多的三种方式

7、高级

(1)聚合、分组

##聚合

# 语法:
aggregate(别名=聚合函数('字段'))
 
# 规则:
1.可以同时对多个字段进行聚合处理:aggregate(别名1=聚合函数1('字段1'), ..., 别名n=聚合函数n('字段n'))
3.是QuerySet对象方法
2.方法返回值返回值为dict类型
 
# 案例:所有书中最贵的书的价格
Book.objects.all().aggregate(high_price=Max('price'))



##分组

# 语法:
values('分组字段').annotate(别名=聚合函数('字段')).filter(聚合字段别名条件).values('取分组字段', '取聚合字段别名')
# 规则:
1.values(...).annotate(...)为分组组合,values控制分组字段,annotate控制聚合字段
2.values可按多个字段分组values('分组字段1', ..., '分组字段n'),??如果省略代表按操作表的主键分组
3.可以同时对多个字段进行聚合处理annotate(别名1=聚合函数1('字段1'), ..., 别名n=聚合函数n('字段n'))
4.分组后的的filter代表having判断,只对聚合字段进行条件判断,可以省略(对非聚合字段或分组字段进行条件判断代表where判断)
5.取字段值values(...)省略默认取所有分组字段与聚合字段,也可以自主取个别分组字段及聚合字段(取字段的values中出现了非分组或非聚合字段,该字段自动成为分组字段)
# 案例:每个出版社出版的最贵的书的价格高于50元的出版社名与最高价格
Book.objects.all().values('publish__name').annotate(high_price=Max('price')).filter(high_price__gt=50).values('publish__name', 'high_price')

分组与聚合
View Code

(2)F和Q

# F
    #
    # from django.db.models import F
    # models.Tb1.objects.update(num=F('num')+1)


# Q
    #
    # 方式一:
    # Q(nid__gt=10)
    # Q(nid=8) | Q(nid__gt=10)
    # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
    # 方式二:
    # con = Q()
    # q1 = Q()
    # q1.connector = 'OR'
    # q1.children.append(('id', 1))
    # q1.children.append(('id', 10))
    # q1.children.append(('id', 9))
    # q2 = Q()
    # q2.connector = 'OR'
    # q2.children.append(('c1', 1))
    # q2.children.append(('c1', 10))
    # q2.children.append(('c1', 9))
    # con.add(q1, 'AND')
    # con.add(q2, 'AND')
    #
    # models.Tb1.objects.filter(con)
View Code

(3)事务

from django.db import transaction

with transaction.atomic():
    obj = models.Book.objects.filter(xx).select_for_update()
    xxxxx

8、ORM性能相关

(1)select_related主动连表

# 用户表外键关联角色表
all_users = models.User.objects.all()  # 这样取出来的数据不包含角色表中的信息
for user in all_users:
    print(user.role.name)  # 这样每次循环都会进行一次连表查询,去角色表中找id=user.role_id的值,效率低
all_users = models.User.objects.all().select_related("role")  # 传入需要主动连表的外键字段
# 这样就会一次查询将外键的字段也获取,保存到对象中,可以直接通过点的方式取值
# .values(xxx)虽然也可以一次查询取外键字段,但是保存的是字典,只能通过字典操作,且需要一个一个字段的输入

(2)prefetch_related不主动连表,但是进行多次子查询

all_users = models.User.objects.all().prefetch_related("role")
# 会进行两次查询,第一次查询出所有的用户对象,第二次查询所有id包含在这些用户对象的role_id中的角色,两次查询的速度比连表查询快

(3)only和defer

only的作用和values基本一致,但是values得到的是字典,only得到的是对象,里面保存了想要得到的字段

defer就是反作用,不取哪些字段

9、Content-Type表

https://blog.csdn.net/aaronthon/article/details/81714496

用来解决一张表和多张表建立外键关系的需求。

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation

class Food(models.Model):
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")

class Fruit(models.Model):
    name = models.CharField(max_length=32)
    coupons = GenericRelation(to="Coupon")

class Coupon(models.Model):
    title = models.CharField(max_length=32)
    content_type = models.ForeignKey("ContentType")  # 关联ContentType表
    object_id = models.IntegerField()  # 定位对应表的id
    # 这个属性不创建字段,只是用来方便查询,只需要将对应的对象传给content_obj,就能自动找到content_type中的对象并定位到id
    content_obj = GenericForeignKey("content_type", "object_id")
models.py
food_obj = Food.objects.filter(id=1).first()
Coupon.objects.create(title="酱香饼买一送小威",content_object=food_obj)

food_obj = Food.objects.filter(id=1).first()
print(food_obj.coupons.all())
正反查询和创建

 

五、cookie和session

1、cookie

保存在浏览器上的键值对,因为http请求没有状态,每一次请求都是独立的,所以需要服务器给客户端发送一个键值对,保存在客户端浏览器上,这样以后每次请求都能验证。

# 设置cookie
response.set_cookie(key, value)

# 获取cookie
request.COOKIES[keys]

# 删除cookie
response.delete_cookie(key)

2、session

由于cookie是保存在浏览器中,数据不安全,且长度有限制,所以session将键值对保存在服务器中,保证无数据的安全。

session依赖于cookie,他把随机字符串作为一个大字典的键,把数据都存储在这个大字典中,字典存储在服务端,而把这个随机字符串作为cookie的值传给客户端,所以客户端只拿到这个随机值,通过这个值去服务端取数据。

注意:session默认保存在数据库中,需要创建数据库信息,才能把键值对存储在数据库中,不然无法使用,记得makemigrations

request.session.set(key, value)
request.session.get(key)
del request.session["key"]

request.session.session_key    #获取用户的随机字符串
request.session.delete(session_key)    #删除当前用户的所有session数据
request.session.flush()  #删除session和cookie

 

六、中间件

是在全局范围内修改请求和响应对象

from django.utils.deprecation import MiddlewareMixin

class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # 在路由之前执行,
        # 返回None继续,返回HttpResponse则不继续

    def process_view(self, request, viewfunc, view_args, view_kwargs):
        # 在路由匹配之后,视图函数之前执行
        # 放回None继续,返回HttpResponse则直接跳到process_response

    def process_response(self, request, response):
        # response可能是视图函数返回的,也可能是其他的中间件返回的

    def process_exception(self, request, exception):
        # 返回None则交给下一个,都是None则交给Django处理异常
        # 返回Response对象,则后面不再执行此方法

    def process_template_response(self, request, response):
        # 视图中必须返回render
        

Django的请求声明周期:

WSGI接收请求并封装成request对象 ---- -执行中间件中的process_request方法 ----- 路由匹配 ----- process_view方法 ----- 视图函数(数据库,模板) ----- 中间件中的process_response方法  ----- 还给WSGI

 

七、ajax

ajax是js的技术,与服务器进行交互,特点:异步,局部刷新

     function AjaxSubmit(){
         var host = '1.1.1.1';
         var port = '1111';
         $.ajax({
             url:"/app01/ajax_submit/",
             type:'POST',
             data:{host:host,port:port},
             success: function (arg) {
             }
         });
     }
function AjaxSubmit_set(){
         var data_list = [
             {'name':'chenchao','age':18},
             {'name':'lisi','age':19},
             {'name':'wangwu','age':13}
 
         ];
 
         $.ajax({
             url:"/app01/ajax_submit_set/",
             type:'POST',
             tradition:true,   原生模式
             data:{data:JSON.stringify(data_list)},
             success: function (arg) {
             }
         });
     }
发送列表
//ajax上传注册信息并获取错误信息
    $("#register-btn").click(function(){

        //ajax上传文件,data部分必须用对象
        var formData = new FormData();
        formData.append("username",$("#id_username").val());
        formData.append("password",$("#id_password").val());
        formData.append("re_pwd",$("#id_re_pwd").val());
        formData.append("email",$("#id_email").val());
        formData.append("avatar",$("#id_avatar")[0].files[0]);
        formData.append("csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val());

        $.ajax({
            url:"/register/",
            type:"post",
            //ajax上传文件需要加两个参数
            processData:false,
            contentType:false,
            data:formData,
            success:function(data){
                if(data.status){
                    //如果有错误,则返回错误信息
                    $.each(data.msg,function(k,v){
                        //k是键,v是值,但是v是列表,错误信息可能有多个
                        $("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error");
                    })
                }else{
                    //如果没有错误,则跳转到指定页面
                    location.href = "/login/"
                }
            }
        })
    })

//输入框取得焦点时,清楚错误信息
    $("form input").focus(function(){
        $(this).next("span").text("").parent().parent().removeClass("has-error");
    });
发送文件

 

八、form组件

1、Form

import re
from django import forms
from django.core.exceptions import ValidationError


def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')


class PublishForm(forms.Form):

    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )

    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))

    title = forms.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': u'标题不能为空',
                                            'min_length': u'标题最少为5个字符',
                                            'max_length': u'标题最多为20个字符'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'标题5-20个字符'}))

    memo = forms.CharField(required=False,
                           max_length=256,
                           widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))

    phone = forms.CharField(validators=[mobile_validate, ],
                            error_messages={'required': u'手机不能为空'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))

    email = forms.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
form.py
def publish(request):
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
    if request.method == 'POST':
        request_form = PublishForm(request.POST)
        if request_form.is_valid():
            request_dict = request_form.clean()
            print request_dict
            ret['status'] = True
        else:
            error_msg = request_form.errors.as_json()
            ret['error'] = json.loads(error_msg)
    return HttpResponse(json.dumps(ret))
视图
from django import forms

class LoginForm(forms.Form):
    username = forms.CharField(label='username', max_length=100)
    password = forms.CharField(label='password', max_length=100)
    
    #钩子函数为对应字段添加判断条件
    def clean_username(self):
        if len(self.cleaned_data.get("username"))>5:
            print(self.cleaned_data.get("password"))
            return self.cleaned_data.get("username")
    def clean_password(self):
        pass
    #全局钩子函数
    def clean(self):
        if self.cleaned_data["password"] == self.cleaned_data["repeat_password"]:
            return self.cleaned_data
钩子函数

2、ModelForm

class BaseForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args,**kwargs)
        for field in self.fields.values():
            field.widget.attrs.update({"class": "form-control"})

class RegForm(BaseForm):
    re_password = forms.CharField(
        label='确认密码',
        widget=forms.widgets.PasswordInput(),
        error_messages={
            "required": "请确认密码"
        }
    )

    class Meta:
        model = models.User
        fields = ["username", "password", "re_password", "name", "phone", "department"]

        widgets = {
            "password": forms.widgets.PasswordInput
        }
        labels = {
            "password": "密码"
        }
        error_messages = {
            "password": {"required": "请输入密码"},
            "username": {"required": "请输入昵称"},
            "name": {"required": "请输入姓名"},
        }

    def clean_username(self):
        username = self.cleaned_data["username"]
        if models.User.objects.filter(username=username):
            self.add_error("username", "该昵称已被注册")
            raise ValidationError("昵称已被注册")
        else:
            return self.cleaned_data["username"]

    def clean(self):
        pwd = self.cleaned_data.get("password")
        re_pwd = self.cleaned_data.get("re_password")
        if pwd == re_pwd:
            return self.cleaned_data
        self.add_error("re_password", "两次密码不一致")
        raise ValidationError("两次密码不一致")
ModelForm

3、formset

注意:使用formset和modelformset需要在模板中写上:{{ xxformset.management_form }},在使用modelformset时,需要在模板中把所有字段都写上,可以隐藏。

from django.forms import formset_factory

# 可以帮助我们创建多个表单,并且同时更新

FormSet = formset_factory(forms.StudyRecordForm, extract=0)
form_set = FormSet(initial=[{"xx": xx}, {"xx": xx}])  # 传入initial代表数据库中没有,但是想让页面中默认显示的内容
if request.method == "POST":
    form_set = FormSet(request.POST)
    if form_set.is_valid():
        form_set.save()
formset用来添加多条记录

4、modelformset

from django.forms import modelformset_factory

# 可以帮助我们创建多个表单,并且同时更新

FormSet = modelformset_factory(models.StudyRecord, forms.StudyRecordForm, extract=0)
obj_list = models.StudyRecord.object.all()
form_set = FormSet(queryset=obj_list)  # 传入queryset代表数据库中有的数据
if request.method == "POST":
    form_set = FormSet(request.POST)
    if form_set.is_valid():
        form_set.save()
modelformset用来编辑多条记录 

 

九、auth组件

1、继承AbstractUser

from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
    """
    用户信息表
    """
    nid = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=11, null=True, unique=True)
    
    def __str__(self):
        return self.username

2、在settings中配置

# 引用Django自带的User表,继承使用时需要设置
AUTH_USER_MODEL = "app名.UserInfo"

3、使用(必须创建了auth表才能使用)

from django.contrib import auth
from django.contrib.auth.models import User
from django.shortcuts import render,redirect


# 创建用户
User.objects.create_superuser(.......)      #创建超级用户
Use.objects.create_user(....)      #创建普通用户
# 这样创建的数据,密码是密文形式,直接create密码是明文
# 验证登陆 def index(request): if request.user.is_authenticated: username = request.user.username return render(request,"index.html",locals()) return redirect("/login") def login(request): if request.method=="POST": username=request.POST.get("username") password=request.POST.get("password") user = auth.authenticate(username=username,password=password) auth.login(request,user) if user: return redirect("/index") else: return render(request,"login.html") return render(request,"login.html",locals()) def logout(request): auth.logout(request) return redirect("/login")

 

 十、配置media

MEDIA_URL = "media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
from django.views.static import serve
# media路径配置
url(r'media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT})

 

 

posted @ 2019-05-28 09:31  不可思议的猪  阅读(535)  评论(0编辑  收藏  举报