小司机带您拟: Django+Xadmin打造在线教育平台[Python2&3通用 ](三)-3&4&5

3-3 django orm介绍与model设计

上节科目完成后代码(来修本节前置条件):

github仓库地址:https://github.com/mtianyan/DjangoGetStarted

  • 针对许commit: 留言板前端页面显示。本次内容了教程3-2竣工。

唯恐现在若还于经过手写sql语句来操作数据库,当我们发了orm,数据库操作变得十分粗略。这等同略节咱们来学学Django中的orm。


原生sql 与 orm

从不orm 的状况下message/views.py代码:

import MySQLdb

# 使用原生sql获取书的列表
def book_list(request):
    # 创建到数据库的连接: 指明用户名,数据库,密码
    db = MySQLdb.connect(user = 'me', db='mydb', passwd='secret', host='localhost')
    # 创建一个游标对象执行器
    cursor = db.cursor()
    # 书写我们需要的sql语句
    cursor.execute('SELECT name FROM books ORDER BY name')
    # 对于fetchall()的结果做遍历,将遍历回来的结果当做数组,取第0个值name。
    names = [row[0] for row in cursor.fetchall()]
    db.close()

仝可以让数据库字段的询问以及采用类似的一个性质一样简单?没错登登登:orm上场了

book:name

book.name
book.save()

Django的orm就是为让咱们不再写点那样的说话,而是如要操作数据库像使用类和类属性一样。

参照文章

  • Base64

  • Base64编码/解码

  • 填充算法,mac与java的分

  • 片密码的工作模式

  • 分组密码

  • PKCS


创立我们的models

verbose_name:对象的人类可读的名目,单数:

verbose_name = "pizza"

class Meta,内嵌于 UserMessage 这个类的定义中
如果 class Publisher 是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统
你可以在任意一个 模型 类中使用 Meta 类,来设置一些与特定模型相关的选项。
如:设置ordering = ['name'],默认地都会按 name 字段排序

message/models.py:

# 继承于django.db.models.Model
class UserMessage(models.Model):
    # 设置最大长度,verbose_name在后台显示字段会用到
    name = models.CharField(max_length=20, verbose_name=u"用户名")
    # Django提供内置的邮箱字段会帮忙验证` default_validators = [validators.validate_email]`
    email = models.EmailField(verbose_name=u"邮箱")
    address = models.CharField(max_length=100, verbose_name=u"联系地址")
    message = models.CharField(max_length=500, verbose_name=u"留言信息")


    class Meta:
        verbose_name = u"用户留言信息"
        # db_table ,这里我们让它自动生成所以不用指定

这会儿我们实施makemigrations messages见面发现并无改动。

mark

因setting中我们从没注册我们的app: message

注意:新建的app都要在setting中注册

Base64编码

据我说知,苹果并没有提供API来是实现Base64编码,所以需要看官在网上寻找验证,还好,这并不难

感谢Lonely__和angelababa的提示,苹果是有Base64的API,截图如下:

苹果提供Base64API.png

Base64编码的思索是凡使用64个基本的ASCII码字符对数据进行重新编码。它将急需编码的数额拆分成字节数组。以3个字节为同一组。按顺序排列24 位数据,再管当下24各项数据分为4组,即每组6位。再于每组的之最高位前补两个0凑足一个字节。这样就把一个3字节为一组的数据重新编码成了4个字节。当所假设编码的多少的字节数不是3底整倍数,也就是说在分组时最后一组不足够3单字节。这时在最后一组填充1到2只0字节。并当结尾编码完成后在最终添加1到2独
“=”。

例:将对ABC进行BASE64编码:

1、首先取ABC对应的ASCII码值。A(65)B(66)C(67);

2、再得到二上制值A(01000001)B(01000010)C(01000011);

3、然后拿当时三独字节的二进制码接起来(010000010100001001000011);

4、
再因6个为单位分为4单数据块,并于最高位填充两个0后形成4只字节的编码后底值,(00010000)(00010100)(00001001)(00000011),其中加色部分也实际数据;

5、再将当时四单字节数据转发成10上前制数得(16)(20)(9)(3);

6、最后因BASE64给出的64个主导字符表,查出对应之ASCII码字符(Q)(U)(J)(D),这里的价实际就是是数额以字符表中的目录。

Base64编码表

解码过程就是是将4只字节再还原成3个字节再根据不同之多寡形式把字节数组重新整理成多少。

Base64很直观的目的就是是为二进制文件转发为64单中心的ASCII码字符。

于setting中注册我们的app

DjangoGetStarted/settings.py 大概36行INSTALLED_APPS:

`INSTALLED_APPS`
[
    前面的不用变,后面新增下一行
    'message'
]

这时候我们再次运行Tools 菜单下 Run manage.py Task会提示:

如若提示:

SyntaxError: Non-ASCII character '\xe7' in file D:\CodeSpace\PythonProject\DjangoGetStarted\apps\message\models.py on line

求小心或而忘掉在描写过中文的地方长:

#coding: utf-8

小心要加以于第一还是二行。

接下来实施下发号施令:

makemigrations message

mark

migrate message 生成数据表

mark

前往Navicat验证:

mark

得看到咱们的数据表已经创办成功。默认数据表名称为app名称_类名转换为小写
自动生成的id作为主键。

AES

系统也并没有直接提供诸如DES、AES的API,但是提供了加密解密之相干操作CommonCrypto,DES或者AES的实现,需要我们和好包一下。

加密凡是出于算法/模式/填充组合的,算法是DES,AES等,
模式是EBC,CBC等,iOS和Android的填写是不平等的:

mac支持:

NoPadding (NoPadding就是勿填充,相当给从定义填充)

PKCS7Padding

而java支持:

NoPadding

ISO10126Padding

OAEPPadding, OAEPWith<digest>And<mgf>Padding

PKCS1Padding

PKCS5Padding

SSL3Padding

搭下去我们引入一些背景知识:

在密码学中,分组加密(Block
cipher,又如分块加密),是同样栽对称密钥算法。它以公开分成基本上单当丰富之模块(block),使用规定的算法和针对如密钥对每组分别加密解密。分组加密是极其重要的加密协议组成,其中典型的如DES和AES作为美国政府核定的正规加密算法,应用领域从电子邮件加密至银行贸易转帐,非常广阔。

密码学中的工作模式:

无限早出现的劳作模式,ECB,CBC,OFB和CFB可以追溯到1981年。2001年,NIST修订了那先发布之干活模式工作列表,加入了AES,并加入了CTR模式。最后,在2010年1月,NIST加入了XTS-AES,而别的可信模式并无为NIST所认证。例如CTS是一模一样种植密文窃取之模式,许多广的密码学运行库提供了这种模式。

密码学中,块密码的做事模式允许用与一个片密码密钥对多于一片的数开展加密,并确保其安全性。块密码自身只能加密长度等密码块长的单块数据,若要加密变长数据,则数必须先叫划分也局部独立的密码块。通常而言,最后一块数据吧待运用合适填充方式将数据扩展至副密码块大小的尺寸。一种植工作模式描述了加密每一样数据块的长河,并不时用基于一个寻常称为初始化向量的叠加输入值为拓展随机化,以担保安全。

初始化向量

初始化向量(IV,Initialization
Vector)是成百上千干活模式受到用来随机化加密的等同块数据,因此可由同的公开,相同之密钥产生不同之密文,而不论需再次有密钥,避免了一般相当复杂的即刻同样进程。

初始化向量与密钥相比有差之安全性要求,因此IV通常并非保密,然而在大部情景被,不应有在动同样密钥的景况下零星涂鸦利用与一个IV。对于CBC和CFB,重用IV会导致泄露明文首独片的某些信息,亦包括个别只不等消息遭到千篇一律之前缀。对于OFB和CTR而言,重用IV会导致了失去安全性。另外,在CBC模式受到,IV在加密常常务必是无能为力预计的;特别的,在成千上万实现中以的出IV的法,例如SSL2.0使的,即采取上一个信之尾声一片密文作为下一个消息之IV,是匪安全之。

小心:ECB模式不需初始化向量,之所以提一句,是为自己于是的ECB模式。

填充

片密码只能针对确定长度的多寡块进行处理,而消息的长一般是可变的。因此有模式(即ECB和CBC)需要最后一块当加密前进行填空。有数种填充方法,其中最为简易的一模一样种植是当平文的末段填充空字符以要该长为片长的平头加倍,但要管可以回复平文的老长度;例如,若平文是C语言风格的字符串,则只出失误尾会有空字符。稍微复杂一点的章程虽然是故之DES使用的计,即以数码后补偿加一个1位,再续加足够的0位直到满足块长的求;若消息长度刚好符合块长,则增长一个填写充块。最复杂的虽是针对性CBC的措施,例如密文窃取,残块终结等,不见面起额外的密文,但会大增一些复杂度。布鲁斯·施奈尔及尼尔斯·弗格森提出了简单栽简易的可能:添加一个值也128的字节(十六进制的80),再为0字节填写满最后一个片;或朝向最终一个片填充n个值均为n的字节。

CFB,OFB和CTR模式不欲对长不也密码块大小整数加倍之音进行特别之处理。因为这些模式是经过对块密码的出口以及平文进行异或工作之。最后一个平文块(可能是勿整的)与密钥流块的前几乎只字节异或后,产生了和该平文块大小同等之密文块。流密码的这特性使得其可以在急需密文和平文数据长严格等的场所,也得以利用在以流动式传输数据而非便宜进行填的场合。

只顾:ECB模式是要填写的。

ECB:
尽简单易行的加密模式就是为电子密码本(Electronic
codebook,ECB)模式。需要加密的信息据块密码的块大小为分成数单片,并对每个片进行独立加密。

ECB加密

ECB解密

本方的症结在于同的平文块会叫加密成相同的密文块;因此,它不可知怪好的隐形数据模式。在少数场合,这种办法无可知提供严格的数码保密性,因此并无引进用于密码协议被。下面的例证显示了ECB在密文中显得平文的模式的档次:该图像的一个位图版本(上图)通过ECB模式或者会见让加密成中图,而非ECB模式通常会拿其加密成极下图。

原图

应用ECB模式加密

提供了伪随机性的非ECB模式

原图是运用CBC,CTR或外其它的再度安全之模式加密最下图或发生的结果——与随机噪声无异。注意最下图看起的随机性并无克代表图像已经为安康之加密;许多勿安全之加密法也恐怕发生这种“随机的”输出。

ECB模式也会招致使用其的说道不可知提供数据完整性保护,易遭受重放攻击的震慑,因此每个片是坐完全相同的方式解密之。例如,“梦幻之星在线:蓝色脉冲”在线电子游戏以ECB模式之Blowfish密码。在密钥交换系统被破解而出更简短的破解方式前,作弊者重复通过发送加密的“杀死怪物”消息包以私的飞跃增加阅历值。

其他模式于此就无进行了,详情请转片密码的做事模式
,进一步询问CBC、CFB、OFB、CTR等模式。

将最好紧要的函数摘出来解释一下:

/*!
    @function   CCCrypt
    @abstract   Stateless, one-shot encrypt or decrypt operation.
                This basically performs a sequence of CCCrytorCreate(),
                CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().

    @param      alg             Defines the encryption algorithm.


    @param      op              Defines the basic operation: kCCEncrypt or
                    kCCDecrypt.

    @param      options         A word of flags defining options. See discussion
                                for the CCOptions type.

    @param      key             Raw key material, length keyLength bytes. 

    @param      keyLength       Length of key material. Must be appropriate 
                                for the select algorithm. Some algorithms may 
                                provide for varying key lengths.

    @param      iv              Initialization vector, optional. Used for 
                                Cipher Block Chaining (CBC) mode. If present, 
                                must be the same length as the selected 
                                algorithm's block size. If CBC mode is
                                selected (by the absence of any mode bits in 
                                the options flags) and no IV is present, a 
                                NULL (all zeroes) IV will be used. This is 
                                ignored if ECB mode is used or if a stream 
                                cipher algorithm is selected. 

    @param      dataIn          Data to encrypt or decrypt, length dataInLength 
                                bytes. 

    @param      dataInLength    Length of data to encrypt or decrypt.

    @param      dataOut         Result is written here. Allocated by caller. 
                                Encryption and decryption can be performed
                                "in-place", with the same buffer used for 
                                input and output. 

    @param      dataOutAvailable The size of the dataOut buffer in bytes.  

    @param      dataOutMoved    On successful return, the number of bytes
                    written to dataOut. If kCCBufferTooSmall is
                returned as a result of insufficient buffer
                space being provided, the required buffer space
                is returned here. 

    @result     kCCBufferTooSmall indicates insufficent space in the dataOut
                                buffer. In this case, the *dataOutMoved 
                                parameter will indicate the size of the buffer
                                needed to complete the operation. The 
                                operation can be retried with minimal runtime 
                                penalty. 
                kCCAlignmentError indicates that dataInLength was not properly 
                                aligned. This can only be returned for block 
                                ciphers, and then only when decrypting or when 
                                encrypting with block with padding disabled. 
                kCCDecodeError  Indicates improperly formatted ciphertext or
                                a "wrong key" error; occurs only during decrypt
                                operations. 
 */  

CCCryptorStatus CCCrypt(
    CCOperation op,         /* 枚举值,确认是加密操作,还是解密操作 */
    CCAlgorithm alg,        /* 枚举值,确认加解密的算法,如kCCAlgorithmAES128、kCCAlgorithmDES */
    CCOptions options,      /* 枚举值,kCCOptionPKCS7Padding | kCCOptionECBMode,经我调查,这样就是ECB模式,并以PKCS7来填充*/
    const void *key,
    size_t keyLength,
    const void *iv,         /* 初始化向量(NULLoptional initialization vector),ECB模式写NULL就行 */
    const void *dataIn,     /* optional per op and alg */
    size_t dataInLength,
    void *dataOut,          /* data RETURNED here */
    size_t dataOutAvailable,
    size_t *dataOutMoved)  

点说及,iOS和Android填充是无同等的,那怎么收拾?据说,PKCS7Padding是兼容PKCS5Padding的,我当跟安卓同测试中,确实没问题。

拿自身因此底AES加密摘出来吧:

本身为此的凡一个NSData类目NSData+AES,密钥是128各的,即16只字节,加密解密方法的落实如下(记得引#import <CommonCrypto/CommonCryptor.h>):

加密:

- (NSData *)AES128EncryptWithKey:(NSString *)key
{
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}  

解密:

- (NSData *)AES128DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding| kCCOptionECBMode,
                                          keyPtr, kCCKeySizeAES128,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}  

Models讲解

除过普通的附和数据库的字段类型如CharField,还有众多尖端项目。如EmailField提供email验证。

    models.ForeignKey     # 外键
    models.DateTimeField  # 时间字段
    models.IntegerField   # 整型
    models.IPAddressField # IP地址
    models.FileField      # 上传文件
    models.ImageField     # 图片

ctrl按停+左键点击models
进入下点击fields蘑菇到文件开始好见到有着字段:

__all__ = [str(x) for x in (
    'AutoField', 'BLANK_CHOICE_DASH', 'BigIntegerField', 'BinaryField',
    'BooleanField', 'CharField', 'CommaSeparatedIntegerField', 'DateField',
    'DateTimeField', 'DecimalField', 'DurationField', 'EmailField', 'Empty',
    'Field', 'FieldDoesNotExist', 'FilePathField', 'FloatField',
    'GenericIPAddressField', 'IPAddressField', 'IntegerField', 'NOT_PROVIDED',
    'NullBooleanField', 'PositiveIntegerField', 'PositiveSmallIntegerField',
    'SlugField', 'SmallIntegerField', 'TextField', 'TimeField', 'URLField',
    'UUIDField',
)]

介绍字段参数

CharField总得指明默认最要命尺寸。null=True,blank=True指明字段可以呢空
defalut = " "依赖定默认值。

name = models.CharField(max_length=20,null=True,blank=True, verbose_name=u"用户名")

id是自动生成的,如果欲打定义主键,message/models.py中上加字段:

object_id = models.CharField(primary_key=True, verbose_name="主键")

这会儿点击Tools 菜单下 Run manage.py Task输入makemigrations message

mark

知识点:CharField必须指明最要命尺寸

object_id改为:

    object_id = models.CharField(primary_key=True, max_length=50 ,verbose_name="主键")

此时点击Tools 菜单下 Run manage.py Task输入makemigrations message

You are trying to add a non-nullable field 'object_id' to usermessage without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py

依据提示信息,我们需要让object_id补加默认值:

    object_id = models.CharField(primary_key=True, max_length=50,default="", verbose_name="主键")

get新知识点:object_id必须有默认值

输入2 退出:然后输入makemigrations message

mark

更输入下面发号施令生成数据表

migrate message 

好看看上图过程被见面报告我们做了何等变化,如删减了默认系统生成的主键id
,变更了name。新增了咱的object_id

通往Navicat验证右键设计表:

mark

可以视object_id一度变为我们的初主键。

介绍Meta信息:

Meta信息遭我们得指定常见的品类:

db_table = "user_meassage"

自从定义后生成表,表名会与我们的保持一致。而休见面前缀appname如:message_

这边为咱们曾好成了了,就绝不做验证改变表名了。

ordering = '-object_id'

ordering指定默认排序字段,如:就见面因为object_id倒序

verbose_name_plural = u"用户留言信息"

verbose_name_plural:复数信息,便于人读。否则会于后台显示用户留言信息s

就修完了orm用数据表映射表。
github地址:https://github.com/mtianyan/DjangoGetStarted
此节终结对许github commit:

留言板数据库orm映射成表完成。内容了教程3-3完。

3-4 django model的增删改

github仓库地址:https://github.com/mtianyan/DjangoGetStarted

  • 达小节完成代码对应commit:
    留言板数据库orm映射成表完成。内容了教程3-3终了。

message/views.py中:

from .models import UserMessage

拿我们刚创建的model,import进来。.代表是跟时同级的目。

比如下图所显示添加同修测试数据。

mark

然后还我们的getform方法中添加下代码:

def getform(request):
    # UserMessage默认的数据管理器objects。
    # 方法all()是将所有数据返回成一个queryset类型(django的内置类型)
    all_message = UserMessage.objects.all()

    #我们可以对于all_message进行遍历操作
    for message in all_message:
        # 每个message实际就是一个UserMessage对象(这时我们就可以使用对象的相关方法)。
        print message.name

    return render(request, 'message_form.html')

调剂过程:

mark

  • 点击上图小红框位置,打及断点。

  • 点击Run -> debug后:在浏览器里打开:http://127.0.0.1:8000/form/

mark

  • 弹来上图表示曾经跻身断点。

mark

  • 这时鼠标左键点击:all_message.可以观看这是一个{QuerySet}类型的对象,里面存放着[<UserMessage: UserMessage object>]

  • f6苟运行至下一致步。此时凡的值窗口内可以望message的价值。说明我们成博得到了数据库的价。

mark

filter取出指定要求值

all_message = UserMessage.objects.filter(name=' mtianyan', address='西安')

mark

本点调试过程又调试好见到我们一致取出了价值。

稍稍练:将名字改成呢同协调数据库存放值不同之。查看结果。

mark

成了空列表,说明一切对。

以数据存入数据库

叩问:django/db/models/base.py 源码中提供save方法

def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):

getform方法被补充加代码:

 # 存储部分

    # 首先实例化一个对象
    user_message = UserMessage()

    # 为对象增加属性
    user_message.name = "mtianyan2"
    user_message.message = "blog.mtianyan.cn"
    user_message.address = "西安"
    user_message.email = "1147727180@qq.com"
    user_message.object_id = "efgh"

    # 调用save方法进行保存
    user_message.save()
  • 自从上断点:如下图。

mark

  • 直接惦记f6独自步调试,直到如下图:蓝色到return语句

mark

可以于生方值窗口查到值

mark

Navicat进行验证

足看成功的补加了多少mtianyan2

mark

何以从html的交付中收获到数并保存进数据库

templates/message_form.html:

mark

method是post。action就是依为我们以urls.py中安排的/form/
前必须加以斜杠指根路径下form
其中的input会自动把价值传递给后台:这时我们虽可以以getform中赢得到刚刚传递过来的价值。

运作品种:然后输入需要填的价值。点击提交:出现403错

Forbidden (403)
CSRF verification failed. Request aborted.

冲提示:我们的页面没有展开crsf的认证,这时django的平安体制,不同意任意form都向后台提交。

知识点:所以我们得以html页面被在csrf_token

    {% csrf_token %}

mark

旧那行删除掉。打上断点

mark

刷新页面并交。这时候在价值窗口可以视request对象下的POST中存放着我们提交的数量。内容如下

<QueryDict: {u'message': [u'\u54c8\u54c8'], u'address': [
u'\u897f\u5b89\u5e02'], u'csrfmiddlewaretoken': [
u'uIYSMOTWPJBPOPucRwd3uDaWtCzeEaem'], u'name': [
u'\u5929\u6daf\u660e\u6708\u7b19'], u'email': [u'1147727180@qq.com']}>

mark

数据因dict:key-value 形式储存 key是出于如下图html中之name所主宰对应之。

mark

数据库新增。

request.POST受数量取出,存入user_message对象

 # html表单部分

    # 此处对应html中的method="post",表示我们只处理post请求
    if request.method == "POST":
        # 就是取字典里key对应value值而已。取name,取不到默认空
        name = request.POST.get('name', '')
        message = request.POST.get('message', '')
        address = request.POST.get('address', '')
        email = request.POST.get('email', '')

        # 实例化对象
        user_message = UserMessage()

        # 将html的值传入我们实例化的对象.
        user_message.name = name
        user_message.message = message
        user_message.address = address
        user_message.email = email
        user_message.object_id = "ijkl"

        # 调用save方法进行保存
        user_message.save()
  • 打断点在生图位置:

mark

  • 上调剂:点击点击method:是get请求。因为咱们并无随提交按钮,而是get这个网页

mark

  • 点击f8延续运行我们的档次 浏览器被填入表单内容点提交。

mark

以这次是表单提交,已经改成了post方式。按f6进展单步调试。

一直单步到如下图蓝色

mark

这儿候值浏览窗口可看看

mark

自我批评我们的user_message对象的性质是否都满长进去,

运f8 继续路并前往Navicat验证

mark

足看我们的数据库被都激增,标志在咱已经成功存入数据。

抹数据。

对查询到之数据做去除:

# 方法2 :filter取出指定条件值,逗号代表and 必须同时满足两个条件才返回。
all_message = UserMessage.objects.filter(name='mtianyan', address='西安')

# 我的数据库里保存着可以匹配到该条数据的一行。

# 删除操作:使用delete方法删除all_message

all_message.delete()

    for message in all_message:
        # 删除取到的message对象
        message.detele()
        # print message.name

点击run并访问:http://127.0.0.1:8000/form/
进去Navicat进行求证。

mark

足见到咱们的那么条mtianyan + 西安之数量都为删去。

时至今日:我们都学会了增产,删除,查询。

本节结github对诺commit:

django model的增删改数据库。本次内容了教程3-4。

3-5 django url templates配置

项目Github地址:https://github.com/mtianyan/DjangoGetStarted
本节始对应相应Github的commit:django
model的增删改数据库。本次内容了教程3-4。

本节拿介绍url的布,以及如何用数据库数据填充充回前台html页面。

场景:只允许用户改mtianyan,如果无就增长,如果起就揣使用户可改。

取出数据

message/views.py中的getform方法中

    message = None
    all_message = UserMessage.objects.filter(name='mtianyan', address='西安')

    # if 判断是否存在数据
    if all_message:
        # all_message是一个list,可以使用切片。
        message = all_message[0]

此注意把前面几节写的去除掉

用数据填至html中

修改return render

return render(request, 'message_form.html',{
        "my_message" : message
})   

这边前面的”my_meassage”是咱可自行命名的。会生出一个my_message靶就返回前端页面。

在前端页面中加大入值。

为input系列标签添加value:
使用my_message.name博到我们传递过来的my_message靶的属性值。

        <input id="name" type="text" name="name"  
        value="{{ my_message.name }}" class="error" placeholder="请输入您的姓名"/>

要自行完成姓名,邮箱,联系地址三单input标签。

textarea签添加值

mark

        <textarea id="message" name="message"  
        placeholder="请输入你的建议">{{ my_message.message }}</textarea>

运转项目,访问:http://127.0.0.1:8000/form/

mark

得逞!!我们曾经拿后台数据库数据成功展示及前台。

template模板渲染着之部分用法。

每当我们的template模板被吗便是form.html中,不同意我们写Python的语法,
她提供了同等仿照自己的内建标签。

官文档中template内建标签从而法传送门

常用的几乎种植模板标签介绍:

if - else

法定提供模板如下:

mark

私执行:

mark

满足if运行结果:

mark

不满足if:如改为my_message.name == "mtianyan1"运行结果:

mark

ifequal & ifnotequal

mark

官方文档解释:ifequal a b
相当于f a == b.ifnotequal虽说一定给if a != b

村办执行:

mark

结果吗:未找到中文昵称

slice

mark

合法文档解释:其实就算是片操作。从头开始切到第n单。

个人执行:

mark

本来mtianyanmtianyan1凡是殊的,但是片后前八各相同。
运作结果显示 :对应中文昵称:天涯明月笙

URl的号设置技巧

DjangoGetStarted/urls.py:

r'^form/$'增补加别名:

    url(r'^form/$', getform, name = "form_new")

往html中修改action地址为下所示:

<form action="{% url "form_new" %}" method="post" class="smart-green">

此刻我们若更改urls.py中的r'^form/$'莫欲重修改前端代码中值。

url先后顺序问题

注意url匹配规则遭到毫无疑问毫无忘记/$标志代表因form/终止的才会有效。不见面朝着后继续配合。比如没有/$

    url(r'^form', getform, name="form_new")

此时我们进去浏览器访问时输入http://127.0.0.1:8000/formemmm犹可以叫响应。

mark

专门是设下还部署有给这规则包含的条规,会起让描写以更依靠前之掣肘停得无至正确处理的Bug。

mark

达到图我们是想使为formtest响应admin.site.urls。但是会于form提前拦截停。

为此我们终将要葡京在线开户留心加上/$符号。

迄今我们完成了留言板项目:学习到了Django必备的基础知识。
产同样回我们将启我们的进阶学习:开发在线教育平台网站。

本章结束:

针对许Commit: 留言板项目学好,本次内容了教程3-5。完结,撒花。
项目Github地址:https://github.com/mtianyan/DjangoGetStarted