zoukankan      html  css  js  c++  java
  • django 线上教育平台开发记录

    1、环境搭建

    2、新建项目

      1)、首先通过 django-admin 新建一个项目,(例如项目名为mxonline)

        

    django-admin startproject mxonline

      运行后会出现一个 mxonline的文件夹,这就是整个项目的文件夹,文件夹下的文件结构为:

      2)、进入到 mxonline下的settings.py 文件配置数据库,我自己是这样配置的

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

       然后通过 migrate命令在数据库中会生成初始的数据表

    python manage.py makemigrations
    
    python manage.py migrate

      注意:如果makemigrations出错,一般都是数据库配置错误,请仔细检查

    3、第一个django页面

      运行django

    python manage.py runserver

      然后在浏览器打开 http://127.0.0.1:8000/,就可以看到我么第一个django页面了

    4、app的model设计

      1)新建一个叫users的app,新建完成后,会出现一个和mxonline同级的users文件夹,这就是我们的users 的app

    python manage.py startapp users

      2)设计user的model(users/model.py)

      

    # -*- coding: utf-8 -*-
    from django.db import models from django.contrib.auth.models import AbstractUser from django.utils.encoding import python_2_unicode_compatible python_2_unicode_compatible class UserProfile(AbstractUser): nickname = models.CharField(max_length=16, verbose_name=u'昵称', default="") birday = models.DateField(verbose_name=u'生日', null=True, blank=True) gender = models.CharField(choices=((‘male’,u''),('female',u'')), default="female") address = models.CharField(max_length=64, default="") mobile = models.CharField(max_length=11, null=True, blank=True) image = mdoels.ImageField(upload_to="image/%Y/%m", default = u'image/default.png', max_length=64) class = Meta: verbose_name = "用户信息" verbose_name_plural = verbose_name def __str__(self): return self.username
    #other models
    ...

      3)注册 app,并设置 AUTH_USER_MODEL

      在settings.py中的 INSTALLED_APP中添加 users

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'users',
    ]

    AUTH_USER_MODEL = "users.UserProfile"

      4)因为models中用到了 ImageField,需要安装pillow

        进入虚拟环境,安装pillow

    pip  install pillow

      5)同步user表到数据库

    python manage.py makemigrations
    
    python manage.py migrate

    5、如何将多个app放到一个文件夹apps(apps所在位置为项目根目录)下:

      在settings.py文件中,insert apps路径即可

      首先  

    import sys

      然后在 BASE_DIR 后面添加apps

    sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

     6、创建后台admin的用户

    python manage.py createsuperuser admin

    7、settings.py相关设置

    LANGUAGE_CODE = 'zh-hans'    #修改django后台为中文
    
    TIME_ZONE = 'Asia/Shanghai'    #修改时区
    
    USE_TZ = False  #本地时间,True为国际时间

    8、xadmin(django最好使用1.9.8的版本,pip install django=1.9.8,当然自动安装很简单)

      1)settings.py修改

    pip install xadmin

      修改settings.py中的配置

      将 xadmin 和 crispy_forms(注意这里的-改为_) 加入到INSTALLED_APPS中

      2)项目urls.py的修改

    # from django.contrib import admin
    import xadmin
    
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^xadmin/', xadmin.site.urls),
    ]

    9、手动安装 xadmin

      1)、下载xadmin源码,xadmin的源码是保存在github上的,在github首页进行搜索,然后下载到本地

      

      2)、新建extra_apps(第三方app)文件夹(与apps文件夹同级),并在该文件夹下新建__init__.py文件(标识为一个可被调用的包)  

        然后打开xadmin的源码,将里面的xadmin目录复制到extra_apps文件夹下

      3)、最后在settings.py文件中将extra_apps添加到项目路径

    sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))

      注意:本人在手动安装后运行项目时,出现了下面的错误

    from future.utils import iteritems
    ImportError: No module named future.utils

      通过网上查询,在github上下载了future相关代码

      然后复制到项目对应虚拟环境的目录下

      我自己对应的目录为:C:\Users\Administrator\Envs\mxonline\Lib\site-packages\

      再次运行项目,又出现ImportError: No module named six 的错误,然后可以通过pip install six的方式解决

      最后, 同步xadmin相关数据表到数据库

    python manage.py makemigrations
    python manage.py migrate

      项目终于成功启动!!!

    10、django邮箱验证登录的实现方式

      views.py文件中,在登录函数上面重写CustomBackend类:

    from django.contrib.auth.backends import ModelBackend
    from django.db.models import Q
    
    from .models import UserProfile
    
    class CustomBackend(ModelBackend):
        def authenticate(self, username=None, password=None, **kwargs):
            try:
                user = UserProfile.objects.get(Q(username=username)|Q(email=username))
                if user.check_password(password):
                    return user
            except Exception as e:
                return None

      然后在settings.py中添加:

    AUTHENTICATION_BACKENDS = (
        'users.views.CustomBackend',
    )

     11、Django验证码 django-simple-captcha 的使用

      1)、安装和配置

      通过pip install 快捷安装

    pip install  django-simple-captcha

      将captcha添加到settings.py文件中的 INSTALLED_APPS中

      同步响应的配置到数据库中(同步后数据库会新建一个名为captcha_captchastore的数据表)

    python manage.py migrate

      最后在项目的urls.py文件中添加:

    urlpatterns += patterns('',
        url(r'^captcha/', include('captcha.urls')),
    )

      2)、添加到表单并在视图函数或试图类验证

      添加到表单

    class RegisterForm(forms.Form):
        password = forms.CharField(required=True, min_length=6)
        email = forms.EmailField()
        captcha = captcha = CaptchaField(error_messages={"invalid":u"验证码错误"})

      模板中添加以显示出验证码

    <div class="form-group marb8 captcha1 {% if register_form.errors.captcha %}errorput{% endif %}">
        <label>&nbsp;&nbsp;</label>
        {{ register_form.captcha }}
    </div>

      验证:

    class RegisterView(View):
        def get(self, request):
            register_form = RegisterForm()
            return render(request, 'register.html',{'register_form':register_form})
        def post(self, request):
            register_form = RegisterForm(request.POST)
            if register_form.is_valid():
         ...

     12、邮箱验证

      1)、首先配置settings.py

    EMAIL_HOST = 'smtp.163.com'
    EMAIL_PORT = 25
    EMAIL_HOST_USER = "abc@163.com"
    EMAIL_HOST_PASSWORD = '123456'
    EMAIL_USE_TLS = False
    EMAIL_FROM = "abc@163.com"

      2)、在app的同级目录中新建一个utils的文件夹(记得新建一个__init__.py文件,将文件夹标记为可引用的包),在utils下新建email_send.py文件用于通过邮箱发送验证信息

    email_send.py

    # -*- coding: utf-8 -*-
    
    from random import Random
    
    from django.core.mail import send_mail
    
    from users.models import EmailVerfyRecord
    from mxonline.settings import EMAIL_FROM
    
    
    def random_str(randomlength=8):
        str = ''
        chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
        length = len(chars) - 1
        random = Random()
        for i in range(randomlength):
            str += chars[random.randint(0, length)]
        return str
    
    def send_email_verification_code(email, send_type="register"):
        email_record = EmailVerfyRecord()
        #生成一个16位数字的验证码
        code = random_str(16)
        email_record.code = code
        email_record.email = email
        email_record.send_type = send_type
        email_record.save()
    
        if send_type == 'register':
            email_title = "暮雪在线网注册激活链接"
            email_body = '请点击链接激活账号:http://127.0.0.1:8000/active/{0}'.format(code)
    
            send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
            if send_status:
                pass

      3)、在注册的处理函数中调用email_send.py中的 send_email_verification_code()函数,以发送验证信息到新用户的注册邮箱

    class RegisterView(View):
        def get(self, request):
        ...
        def post(self, request):
            register_form = RegisterForm(request.POST)
            if register_form.is_valid():
                username = request.POST.get("email", "")
                ...

            user = UserProfile()
            user.username = username
            user.email = username
            user.password = make_password(password)
            user.is_active = False  #注册的时候先将该字段设置为false,通过邮箱验证后再设置为True
            user.save()

                send_email_verification_code(username, 'register')
                return render(request, 'login.html')
            else:
                return render(request, 'register.html', {'register_form':register_form})

      4)、可以看到我们发送给新用户的访问链接中是通过active/ 加上一个16位的随机码来访问的,所以需要在urls.py 和 views.py中添加相应的激活处理

    urls.py

    urlpatterns += url(r'^active/(?P<active_code>[a-zA-Z0-9]{16})/$', ActiveUserView.as_view(), name='active_user')

    views.py

    class ActiveUserView(View):
        def get(self, request, active_code):
            all_record = EmailVerfyRecord.objects.filter(code=active_code)
            for record in all_record:
                email = record.email
                user = UserProfile.objects.get(email=email)
                user.is_active = True
                user.save()
            return render(request, 'login.html')

     13、模板继承:

      注意:模板继承中的 static 标签,即使父模板中load了一次,子模板中还是要load

      子模板中记得要重新加载static标签        {% load staticfiles %}

    14、关于上传图片 media相关的设置

      例如某个model 配置了 image这个字段,用于设置用户头像,是这么定义的:

    image = models.ImageField(upload_to='org/%Y%m', verbose_name=u'logo')

      upload_to指明了上传的路径,然后还需要在settings.py文件中,TEMPLATES添加media的配置,并设置MEDIA_URL 和 MEDIA_ROOT

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, "templates")],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                    'django.core.context_processors.media',
                ],
            },
        },
    ]
    ...
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

      最后在项目的urls.py文件中做如下设置

      

    from organization.views import OrgView
    from mxonline.settings import MEDIA_ROOT
    
    urlpatterns += url(r'^media/(?P<path>.*)$', serve, {"document_root":MEDIA_ROOT})

      完成!

     15、jQuery提示parsererror错误的解决办法

       原因:从服务端返回的json不合法,比如这样的形式,{'name':'xxxx'}。必须是双引号,{"name":"xxxx"}

     这是后端返回给页面的部分代码:json文本部分使用了单引号! 

    class AddUserAskView(View):
        def post(relf, request):
            userask_form = UserAskForm(request.POST)
            if userask_form.is_valid():
                user_ask = userask_form.save(commit=True)   #UserAskForm为一个ModelForm类,相较于Form类,它可以直接提交表单数据到数据库
                return HttpResponse(“{‘status’:'success'}”, content_type='application/json')
            else:
                return ...

      ajax代码如下

    <script>
        $(function(){
            $('#jsStayBtn').on('click', function(){
                $.ajax({
                    cache: false,
                    type: "POST",
                    url:"{% url 'org:add_ask' %}",
                    data:$('#jsStayForm').serialize(),
                    async: true,
                    success: function(data) {
                        if(data.status == 'success'){
                            $('#jsStayForm')[0].reset();
                            alert("提交成功")
                        }else if(data.status == 'fail'){
                            $('#jsCompanyTips').html(data.msg)
                        }
                    },
                    error: function(){
                        alert(arguments[1]);
                    }
                });
            });
        })
    
    </script>

      结果success函数一直不执行,最后添加了error函数后,提示parse error的异常

      最后发现问题,HttpResponse() 中的json文本,一定要用双引号

    return HttpResponse('{"status":"success"}', content_type='application/json')

    16、404页面配置

      1、设置settings.py 文件中 DEBUG 为 false

    DEBUG = False

      2、将DEBUG模式为True的时候,django可以根据设置的STATICFILES_DIRS 取到的静态文件,当设置为false后,这种访问静态文件的方式将会失效(网站部署的时候,静态文件都是通过第三方【apache、nginx等】来代理的。),为了能正常访问静态文件,可以通过配置static的访问配置url和访问函数。

      1)首先在settings.py文件中 ,配置STATIC_ROOT

    STATIC_ROOT = os.path.join(BASE_DIR, 'static')

      2)在项目文件的urls.py文件中,添加static的urls配置

    from mxonline.settings import  STATIC_ROOT
    
    url(r'^static/(?P<path>.*)$', serve, {"document_root":STATIC_ROOT}),

      3)在views.py文件中添加404页面的处理函数

    #全局404处理函数
    def page_not_found(request):
        response = render_to_response('404.html',{})
        response.status_code = 404
        return response

      4)最后在配置url的  urls.py文件中添加404页面的全局配置

    handler404 = 'users.views.page_not_found'

    17、xadmin 使用的图标来自第三方库 awesome

    18、xadmin 中使用ueditor(DjangoEditor源码使用文档)

      1、安装

    pip install DjangoUeditor

      2、在settings.py文件中,添加DjangoUeditor 到INSTALL_APPS里面

      3、urls.py文件中配置url

      

    url(r'^ueditor/',include('DjangoUeditor.urls' )),

      4、models.py 中使用,并在xadmin注册的将其添加到 style_fields

      models.py

    from DjangoUeditor.models import UEditorField
    class Blog(models.Model):
        Name=models.CharField(,max_length=100,blank=True)
        detail=UEditorField(u'内容    ',width=600, height=300, toolbars="full", imagePath="", filePath="", upload_settings={"imageMaxSize":1204000},
                 settings={},command=None,event_handler=myEventHander(),blank=True)

       adminx.py

    class CourseAdmin(object):
      ...#指定在编辑状态不显示的字段
        exclude = ['fav_nums']
        #添加课程时,可以直接添加章节, Lesson 和 CourseResource 均有外键指向Course
        inlines = [LessonInline, CourseResourceInline]
    
        style_fields = {'detail':'ueditor'} 

      5、xadmin下的plugins文件夹中添加ueditor.py文件,然后在__init__.py中的 PLUGINS里面添加 'ueditor'

      ueditor.py文件内容为:

    import xadmin
    from django.db.models import TextField
    from xadmin.views import BaseAdminPlugin, ModelFormAdminView, DetailAdminView
    from DjangoUeditor.models import UEditorField
    from DjangoUeditor.widgets import UEditorWidget
    from django.conf import settings
    
    
    class XadminUEditorWidget(UEditorWidget):
        def __init__(self,**kwargs):
            self.ueditor_options=kwargs
            self.Media.js = None
            super(XadminUEditorWidget,self).__init__(kwargs)
    
    
    class UeditorPlugin(BaseAdminPlugin):
        def get_field_style(self, attrs, db_field, style, **kwargs):
            if style == 'ueditor':
                if isinstance(db_field, UEditorField):
                    widget = db_field.formfield().widget
                    param = {}
                    param.update(widget.ueditor_settings)
                    param.update(widget.attrs)
                    return {'widget': XadminUEditorWidget(**param)}
                if isinstance(db_field, TextField):
                    return {'widget': XadminUEditorWidget}
            return attrs
        def block_extrahead(self, context, nodes):
            js = '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL + "media/ueditor/ueditor.config.js")
            js += '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL + "media/ueditor/ueditor.all.min.js")
            nodes.append(js)
    
    
    xadmin.site.register_plugin(UeditorPlugin, DetailAdminView)
    xadmin.site.register_plugin(UeditorPlugin, ModelFormAdminView)

      __init__.py

    PLUGINS = (
         ...
        'sortablelist',
        'ueditor',
    )

      6、最后需要在展示富文本的地方关掉自动转义

    {% autoescape off %}
    {{ course.detail }}
    {% endautoescape %}

    19、xadmin插件开发之 excel导入

      1、xadmin/plugins中新建excel.py文件

      excel.py

    # -*- coding: utf-8 -*-
    import xadmin
    from xadmin.views import BaseAdminPlugin, ListAdminView
    from django.template import loader
    
    #excel导入功能
    class ListImportExcelPlugin(BaseAdminPlugin):
        import_excel = False
    
        def init_request(self, *args, **kwargs):
            return bool(self.import_excel)  #返回True才会加载插件
    
        def block_top_toolbar(self, context, nodes):    #显示自己的html
            nodes.append(loader.render_to_string('xadmin/excel/model_list.top_toolbar.import.html', context_instance=context))
    
    xadmin.site.register_plugin(ListImportExcelPlugin, ListAdminView)

      2、配置对应的html模板文件

      在xadmin/templates  下新建excel文件夹,然后新建一个html文件,命名为

      model_list.top_toolbar.import.html,

    {% load i18n %}
    <div class="btn-group export">
      <a class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown" href="#">
        <i class="icon-share"></i> 导入 <span class="caret"></span>
      </a>
      <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
          <li><a data-toggle="modal" data-target="#export-modal-import-excel"><i class="icon-circle-arrow-down"></i> 导入 Excel</a></li>
      </ul>
        <script>
            function fileChange(target){
    //检测上传文件的类型
                var imgName = document.all.submit_upload.value;
                var ext,idx;
                if (imgName == ''){
                    document.all.submit_upload_b.disabled=true;
                    alert("请选择需要上传的 xls 文件!");
                    return;
                } else {
                    idx = imgName.lastIndexOf(".");
                    if (idx != -1){
                        ext = imgName.substr(idx+1).toUpperCase();
                        ext = ext.toLowerCase( );
    {#                    alert("ext="+ext);#}
                        if (ext != 'xls' && ext != 'xlsx'){
                            document.all.submit_upload_b.disabled=true;
                            alert("只能上传 .xls 类型的文件!");
                            return;
                        }
                    } else {
                        document.all.submit_upload_b.disabled=true;
                        alert("只能上传 .xls 类型的文件!");
                        return;
                    }
                }
            }
        </script>
        <div id="export-modal-import-excel" class="modal fade">
          <div class="modal-dialog">
            <div class="modal-content">
              <form method="post" action="" enctype="multipart/form-data">
                  {% csrf_token %}
              <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title">导入 Excel</h4>
              </div>
              <div class="modal-body">
                   <input type="file" onchange="fileChange(this)" name="excel" id="submit_upload">
    
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
                <button class="btn btn-success" type="submit" id="submit_upload_b"><i class="icon-share"></i> 导入</button>
              </div>
              </form>
            </div><!-- /.modal-content -->
          </div><!-- /.modal-dalog -->
        </div><!-- /.modal -->
    
    </div>

      3、在plugins/__init__.py文件中添加excel(处理excel导入的文件名称)

      

    PLUGINS = (
        ...
        'ueditor',
        'excel',
    )

      4、在adminx.py文件中对应model注册的时候,设置 import_excel 并重写post()方法以将上传的excel文件解析,最后保存到数据库对应的表中

      这是我的xadmin.py文件中添加了了导入功能的Course的处理

      xlrd第三方库可以通过 pip install xlrd来安装

    import xlrd
    from .models import Course
    ... 
    
    class CourseAdmin(object):
        #Course 中的方法 get_lesson_num 也可以放在展示列表中
        list_display = ['name','desc','detail','degree','learn_time','students','fav_nums','image','click_nums','get_lesson_num','go_to','add_time']
        search_fields = ['name','desc','detail','degree', 'students','fav_nums','image','click_nums']
        list_filter = ['name','desc','detail','degree','learn_time','students','fav_nums','image','click_nums','add_time']
        #根据点击排序
        ordering = ['-click_nums']
        #指定只读(不可修改)的字段
        readonly_fields = ['click_nums']
        #可直接在列表页编辑的字段
        list_editable = ['degree', 'desc']
        #指定在编辑状态不显示的字段
        exclude = ['fav_nums']
        #添加课程时,可以直接添加章节, Lesson 和 CourseResource 均有外键指向Course
        inlines = [LessonInline, CourseResourceInline]
    
        style_fields = {'detail':'ueditor'}
    
        #import_excel位True,excel导入,会覆盖插件中(plugins/excel.py)import_excel的默认值
        import_excel = True
        #将导入的excel文件内容存入数据库的course表中
        def post(self, request, *args, **kwargs):
            if 'excel' in request.FILES:
                wb = xlrd.open_workbook(filename=None, file_contents=request.FILES['excel'].read())
                table = wb.sheets()[0]
                row = table.nrows
                sql_list = []
                org_id_list = []
                for i in xrange(1,row):
                    col = table.row_values(i)
                    sql = Course(
                        degree=col[0],
                        learn_time=col[1],
                        detail=col[2],
                        desc=col[3],
                        students=col[4],
                        fav_nums=col[5],
                        name=col[6],
                        image=col[7],
                        click_nums=col[8],
                        course_org_id=col[10],
                        category=col[11],
                        tag=col[12],
                        teacher_id=col[13],
                        learn_what=col[14],
                        need_know=col[15],
                        notice=col[16],
                        is_banner=col[17],
                    )
                    sql_list.append(sql)
                    org_id_list.append(col[10])
                Course.objects.bulk_create(sql_list)
    
                #更新excel文件中机构包含的课程数
                for id in org_id_list:
                    org = CourseOrg.objects.get(id=int(id))
                    org_course_nums = org.course_set.all().count()
                    org.course_nums = org_course_nums
                    org.save()
    
            return super(CourseAdmin, self).post(request, args, kwargs)
    
        #页面定时刷新,在页面选择
        # refresh_times = [3,5]
    
        #页面展示的数据过滤(只展示符合条件的数据)
        def queryset(self):
            course_ = super(CourseAdmin, self).queryset()
            course_ = course_.filter(is_banner=False)
            return course_
    
        #保存课程时统计课程机构的课程数
        def save_models(self):
            obj = self.new_obj  #新建一个课程对象
            obj.save()
            if obj.course_org is not None:
                course_org = obj.course_org
                course_org.course_nums = Course.objects.filter(course_org=course_org).count()
                course_org.save()
    
    ...

     20、csrf_token 在html 和 js 中写法不一样

      1、js中 当做模板变量  应该用 {{ csrf_token }}

    <script type="text/javascript">
    function add_fav(current_elem, fav_id, fav_type){
        $.ajax({
            cache: false,
            type: "POST",
            url:"{% url 'org:add_fav' %}",
            data:{'fav_id':fav_id, 'fav_type':fav_type},
            async: true,
            beforeSend:function(xhr, settings){
                xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
            },
            success: function(data) {
          ...
            },
        });
    }
    
    $('#jsLeftBtn').on('click', function(){
        add_fav($(this), {{ course.id }}, 1);
    });
    
    $('#jsRightBtn').on('click', function(){
        add_fav($(this), {{ course.course_org.id }}, 2);
    });
    
    
    </script>

      2、html中当做模板标签,应该用 {% csrf_token %}

    <form action="/login/" method="post" autocomplete="off">
        <div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}">
            <label>用&nbsp;户&nbsp;名</label>
            <input name="username" id="account_l" type="text" placeholder="手机号/邮箱" />
        </div>
      ...
         <input class="btn btn-green" id="jsLoginBtn" type="submit" value="立即登录 > " />
    <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' />
    {% csrf_token %}
    </form>
  • 相关阅读:
    【计算机视觉】欧拉角Pitch/Yaw/Roll
    【leetcode】101-Symmetric Tree
    【leetcode】100-Same Tree
    【leetcode】88-Merge Sorted Array
    【leetcode】83-Remove Duplicates from Sorted List
    【leetcode】70-ClimbingStairs
    【计算机视觉】KCF算法
    第1章 Linux系统简介
    第1课 进阶高手的大门
    第3章 在对象之间搬移特性(2):提炼类、类的内联化
  • 原文地址:https://www.cnblogs.com/justbreaking/p/7044483.html
Copyright © 2011-2022 走看看