zoukankan      html  css  js  c++  java
  • py3.6 + xadmin的自学网站搭建

    xadmin安装

      由于安装时需要依赖包并且暂时不支持py3等原因,直接pip install的方法很容易就狗带了。

      说一下我在网上找到的安装方式,在GitHub上有这个项目的开源代码,并且还有很多个版本可以选择。

      克隆一份,clone地址:xadmin,新建一个空白的README.rst代替之前的文件。

      cmd进入dos,执行python setup.py  install,出现gbk解码问题,返回上一步确定README.rst是一个空白文件。这样安装xadmin就完成了。

    狸猫换太子

      算了还是叫太子换狸猫吧,admin文档太少用起来还不如自己写的后台管理,用xadmin更换django自带的admin,安装xadmin的过程与写一个app分支的过程一致。这里我简述一下步骤。

      第一步,创建一个文件包放置xadmin的app,并且将app注册在settings.py文件中。

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'blog',
        'xadmin',
        'crispy_forms',#必须要注册这两个app
    ]

       第二步修改url,用xadmin代替admin。

    from django_extra import xadmin
    from blog import views
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^xadmin/', xadmin.site.urls),
        url(r'^index/', views.index ),
    ]

      这里提醒一下,如果你之前创建好了数据库,在这里使用xadmin之前需要同步一下数据库的相关数据,就是:

    python manage.py makemigrations
    python manage.py migrate

      当然你还需要创建后台管理的超级管理员。

    python manage.py createsuperuser

      当然你觉得英文界面可能对你不够友好,在settings里进行配置,设置为中文,这个与admin操作一致:

    LANGUAGE_CODE = 'zh-hans'
    TIME_ZONE = 'Asia/Shanghai'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = False

       当然我们可以让后台搭建的好看一点:

    class BaseSetting:
        '''
        增加主题样式
        '''
        enable_themes = True
        use_bootswatch = True
    
    
    class GlobalSetting(object):
        '''
        修改标题
    
        '''
        site_title = "jeff后台管理系统"
        site_footer = "http://www.cnblogs.com/Jeffding/"
        menu_style = "accordion"#下拉框收起来
    
    xadmin.site.register(views.BaseAdminView, BaseSetting)
    xadmin.site.register(views.CommAdminView, GlobalSetting)

      后台管理的搭建非常迅速,也非常好用,django的后台管理是根据数据表的管理,所以适用于大多数情况,给我们开发带来了便利。

    登陆注册

      为了使用django后台自带的认证与登陆,所以我们的用户表最好还是继承它的用户表比较好,这样我们登录认证和session写入django都帮我们做好了,所以别人做好的东西,当然是拿来用啦。

      所以我们需要重写user模型。

       第一步,修改settings.py配置文件,覆盖默认的user模型:

    AUTH_USER_MODEL = "users.UserInfo"
    class UserInfo(AbstractUser):
        """
        用户表
        """
        nickname = models.CharField(verbose_name='昵称', max_length=32)
        address = models.CharField(verbose_name='地址', max_length=100)
        cellphone_number = models.CharField(verbose_name='手机号', max_length=11)
        birthday = models.DateField(verbose_name='生日', null=True, blank=True,)
        avatar = models.ImageField(verbose_name='头像', upload_to='static/imgs/%Y/%m',default='static/imgs/default.png')
        create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
        sex_choices = [
            ("male", ""),
            ("female", ""),
        ]
        sex = models.CharField(choices=sex_choices, default='male', verbose_name='性别', max_length=6)
    
        class Meta:
            verbose_name = '用户信息'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.username
    重写model

      衍生的model是继承了AbstractUser的,所以在写的过程中不要写与父类重复的字段(尤其是登陆字段)如果写重复了会导致在哪登陆都无法登陆的情况。

      最后一步别忘了同步数据表。

       这里提一个映射模板的方法,我们可以从视图函数中返回,简洁的写法可以调用TemplateView模块:

    from django.views.generic import TemplateView
    urlpatterns = [
        url(r'^$', TemplateView.as_view(template_name="index.html"), name='index'),
    ]

      我们在模板中可以用name反向找到url,虽然as_view可以将模板直接当作视图函数,但是没办法写试图函数的逻辑处理,所以这种方式使用的并不多。

       正式需要写登陆这样有业务处理逻辑的试图函数url指向view,毕竟django是MVC的框架。

      关于登陆,django自己有一个后台的登陆系统,并且xadmin的登陆是它自己做的,你没有进行配置,我们登陆可以使用这个模块:

    from django.shortcuts import render
    from django.contrib.auth import login as dj_login, authenticate
    
    
    def login(request):
        if request.method == "POST":
            user_name = request.POST.get("username", "")
            pass_word = request.POST.get("password", "")
            user = authenticate(username=user_name, password=pass_word)
            print(user_name, pass_word)
            if user is not None:
                dj_login(request, user)
                return render(request, "index.html", {})
            else:
                return render(request, "login.html", {"msg": "username or password is wrong"})
    
        elif request.method == "GET":
            return render(request, "login.html", {})
    login视图

      避免auth的login方法与我们定义的视图函数名称重复,我们导入时更换函数名。

      如果我们想要使用账号或者邮箱都可以登录,那么我们需要自定义auth方法。django允许我们在配置文件中增加一个变量完成自定义。

      首先,更改配置文件,增加自定义变量:

    AUTHENTICATION_BACKENDS = ('users.views.CustomBackend',)#所以我们还需要在试图函数下定义CustomBackend类

      然后在视图函数中重写ModelBackend的认证方法:

    from django.shortcuts import render
    from django.contrib.auth import login as dj_login, authenticate
    from django.contrib.auth.backends import ModelBackend
    from django.db.models import Q
    from .models import UserInfo
    
    # Create your views here.
    
    
    class CustomBackend(ModelBackend):
        def authenticate(self, username=None, password=None, **kwargs):
            try:
                user = UserInfo.objects.get(Q(username=username) | Q(email=username))#密码存的是密文,不能pwd=pwd
                if user.check_password(password):#这个方法是AbstractUser的校验方法
                    return user
            except Exception as e:
                return None

      使用类的方式进行操作,重写登陆类:

    from django.views.generic.base import View
    class LoginView(View):
        def get(self, request):
            return render(request, "login.html", {})
    
        def post(self, request):
            user_name = request.POST.get("username", "")
            pass_word = request.POST.get("password", "")
            user = authenticate(username=user_name, password=pass_word)
    
            if user is not None:
                dj_login(request, user)
                return render(request, "index.html", {})
            else:
                return render(request, "login.html", {"msg": "用户名或密码错误"})

      url也要改成as_view:

    url(r'^login.html$', views.LoginView.as_view(), name="login"),

       在前端使用{% url 'name'%}会自动生成url得路径,并且静态文件的路径也可以使用这种方式生成:

      开头需要标明:

    {% load staticfiles %}

      对于静态文件地址可自动生成:

    <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">

      验证码自动生成库:

       django-simple-captcha文档:Using django-simple-captcha

      项目GitHub地址:mbi/django-simple-captcha

      让我简单的说就是pip就直接安装好了。

      使用此工具自动生成验证码校验:

      第一步:注册。

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'users',
        'course',
        'organization',
        'operation',
        'xadmin',
        'crispy_forms',
        'captcha',
    ]
    settings.py

      第二步:配置url。

    from django.conf.urls import url, include
    url(r'^captcha/', include('captcha.urls')),
    url.py

      第三步:同步数据库。

      它在我们数据库建了一张表用来存放生成的随机码信息。

      第四步:建立form自动认证。

    from captcha.fields import CaptchaField
    class RegisterForm(Form):
        email = fields.EmailField(required=True)
        password = fields.CharField(required=True,min_length=5)
        captcha = CaptchaField(error_messages={"invalid":"验证码错误"})
    form.py

      第五步,在视图中实例化出对象传到前端。

    class RegisterView(View):
        #显示注册页面
        def get(self,request):
            #把form传给前端,里边是验证码需要在前端显示
            register_form = RegisterForm()
            return render(request,'register.html',{'register_form':register_form})
    view.py

      第六步,在前端自动生成验证码。

    <div class="form-group marb8 captcha1 ">
        <label>验&nbsp;证&nbsp;码</label>
        {{ register_form.captcha }}
    </div>
    register.html

      可以说这个插件比我们之前手写的那个要好用一些。

      根据此判定我们的验证码是否一致。

      注册激活

      邮箱发送验证码

      建一个新的app组件utils组件的新功能就是email_send。

    from users.models import EmailVerifyRecord
    import random, string
    from django.core.mail import send_mail
    from self_study.settings import EMAIL_FROM
    
    
    def send_register_email(email, send_type='register'):
        email_record = EmailVerifyRecord()
        code = random_str(16)
        email_record.code = code
        email_record.email = email
        email_record.send_type = send_type
        email_record.save()
    
        email_title = ''
        email_body = ''
    
        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
    
    
    def random_str(randomlength=8):#生成随机数
        salt = ''.join(random.sample(string.ascii_letters + string.digits, randomlength))
        return salt
    email_send.py
    EMAIL_HOST = 'smtp.sina.com'
    EMAIL_PORT = 25
    EMAIL_HOST_USER = "emailforproject@sina.com"
    EMAIL_HOST_PASSWORD = "********"
    EMAIL_USE_TLS = False
    EMAIL_FROM = "emailforproject@sina.com"
    settings.py
        def post(self,request):#注册提交过来表单的时候,由此接收
            register_form = RegisterForm(request.POST)
            if register_form.is_valid():
                user_name = request.POST.get('email', '')
                #去库里查询有没有这个邮箱,有就是已经注册过了
                if models.UserInfo.objects.filter(email=user_name):
                    return render(request, 'register.html', {'register_form': register_form, 'msg' : '用户已经存在'})
                #没有就是新用户,继续流程
                else:
                    #获取前端填的表单,写进user库里
                    pass_word = request.POST.get('password', '')
                    user_info = models.UserInfo()
                    user_info.username = user_name
                    user_info.email = user_name
                    user_info.password = make_password(pass_word) #加密密码之后再存入库
                    user_info.save()
                send_register_email(user_name,'register')
                return  render(request, 'login.html')
            else:
                return render(request, 'register.html', {'register_form': register_form})#把register_form传给前端是因为 这里包含错误信息,需要在前端显示
    views.py

      拿到链接以后需要注册。

       上传图片

      upload地址:

    image = models.ImageField(upload_to='org/%Y/%m', verbose_name='封面图', max_length=100)

      配置文件中指定文件存储位置:

    MEDIA_URL = '/static/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media/')

      模板中配置:

    <img width="200" height="120" class="scrollLoading" data-url="{{ MEDIA_URL }}{{ org.image }}"/>

      为了让这里的{{ MEDIA_URL}}生效(当然你可以使用手动地址/static/media/{{org.image}}),需要配置setting文件:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
    .......
                    'django.template.context_processors.media',  # 配置html页面获取MEDIA_URL路径
                ],
            },
        },
    ]

      最后前端生成了我们需要的url就会向后端get图片。

    from django.views.static import serve
    from self_study.settings import MEDIA_ROOT
    
    url(r'^static/media/(?P<path>.*)$', serve, {'document_root': MEDIA_ROOT})

       分页组件(django-pure-pagination)

      分页组件的GitHub中有配置的介绍:django-pure-pagination

      先注册,再配置,更改view传给前端,最后在前端进行引用。

    INSTALLED_APPS = [
        'pure_pagination',  # 注册分页app
    ]
    注册
    PAGINATION_SETTINGS = {
        'PAGE_RANGE_DISPLAYED': 10,
        'MARGIN_PAGES_DISPLAYED': 2,
     
        'SHOW_FIRST_PAGE_WHEN_INVALID': True,
    }
    配置
    from pure_pagination import Paginator, PageNotAnInteger
            try:
                page = request.GET.get('page', 1)  # 获取当前页码,如果没有默认1
            except PageNotAnInteger:  # 如果获取页码出错,默认1
                page = 1
    
            p = Paginator(all_orgs, 1, request=request)  # 执行分页函数,参数1数据库的数据,参数2显示多少条数据,参数3request
            orgs_page = p.page(page)  # 返回一个,包含了分页数据和分页导航的对象
            return render(request, 'org-list.html', {'all_orgs': orgs_page})
    View函数
    <div class="pageturn">
             <ul class="pagelist">
                {% if all_orgs.has_previous %}
                     <li class="long"><a href="?{{ all_orgs.previous_page_number.querystring }}" class="prev">上一页</a></li>
                {% endif %}
                {% for page in all_orgs.pages %}
                     {% if page %}
                         {% ifequal page all_orgs.number %}
                             <li class="active"><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
                         {% else %}
                             <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
                         {% endifequal %}
                     {% else %}
                         <li class="none"><a href="">...</a></li>
                     {% endif %}
                {% endfor %}
                 % if all_orgs.has_next %}
                     <li class="long"><a href="?{{ all_orgs.next_page_number.querystring }}" class="next">下一页</a></li>
                 % endif %}
             </ul>
            </div>
    前端分页
  • 相关阅读:
    Jquery 总结的几种常用操作
    Mybatis 一对多
    HTML 子父窗口 iframe 超时 返回首页
    Struts 标签
    Spring + Mybatis 基于注解的事务
    机器学习实战-数据探索(变量变换、生成)
    机器学习实战-数据探索(变量变换、生成)
    Pandas matplotlib 无法显示中文 Ubuntu16.04
    Pandas matplotlib 无法显示中文 Ubuntu16.04
    Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so.
  • 原文地址:https://www.cnblogs.com/Jeffding/p/8093483.html
Copyright © 2011-2022 走看看