注:鉴于 xadmin 的方向调整,可以考虑转为使用simpleui,界面也相当美观
https://github.com/newpanjing/simpleui
本文接Django环境搭建及开发一文,旨在记录一些常用的开发代码避免经常要到官方文档中查看(为方便操作大多在PyCharm[ Tools> Run manage.py Task…]中进行,涉及命令行的可以自行在前面添加python manage.py)。
注:如果在菜单中找不到Run manage.py Task的话,请点击Preferences>Languages & Frameworks>Django在右侧Settings处配置本项目的setting.py文件位置
另外以下内容涉及中文的如使用Python 2.x请自定添加u来指定为utf-8编码
基本操作篇
1.创建App
startapp app_name
2.在系统settings.py的INSTALLED_APPS中添加对应的app_name
class ModelName(models.Model): # 注:xxx = models.DateTimeField(default=datetime.now)时不要在now后加括号
3.编辑所创建App下的models.py(数据表的创建)
makemigrations app_name migrate app_name
createsuperuser创建后台登录的超级用户
4.添加url(urls.py)
from django.views.generic import TemplateView urlpatterns = [ url(r'^xadmin/', xadmin.site.urls), url(r'^$', TemplateView.as_view(template_name='index.html'), name="index"), ]
5. forms和views常用
views.py
# 反向取外键所有数据(_set) yourObject.theModelName_set.all() # 获取url的name并跳转 from django.core.urlresolvers import reverse return HttpResponseRedirect(reverse('index'))
forms.py
class Meta: model = modelName fields = ['field1'...] # 在使用ModelForm时通clean_fieldName来重写该字段验证方法, 在该方法内获取字段值:self.cleaned_data['fieldName']
Settings.py的常见修改
# 将所有app都放到apps下后的设置 import sys sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) # 配置数据库 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'test', 'USER': 'root', 'PASSWORD': 'root', 'HOST': '127.0.0.1', 'OPTIONS': { 'init_command': "SET storage_engine=INNODB;", }, } } # 设置模板目录 TEMPLATES = [ { 'DIRS': [os.path.join(BASE_DIR, 'templates')] }, ] # 设置文字 LANGUAGE_CODE = 'zh-hans' # 设置时区 TIME_ZONE = 'Asia/Shanghai' USE_TZ = False STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) # 设置上传使用的media路径 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 同时配合的配置还有 TEMPLATES = [ { 'OPTIONS': { 'context_processors': [ .... 'django.template.context_processors.media', ], }, }, ] # 设置media路径时应设置urls.py from ProjectName.settings import MEDIA_ROOT from django.views.static import serve url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT}),
用户信息表
用户信息表略有特殊之处:
models.py
from django.contrib.auth.models import AbstractUser # 下面我们使用名称是UserProfile,但如果写用户模块,可以通过如下代码来获取对应的用户表名称 # from django.contrib.auth import get_user_model # User = get_user_model() class UserProfile(AbstractUser): nick_name = models.CharField(max_length=50, verbose_name=u"昵称", default="") birth_day = models.DateField(verbose_name=u"生日", null=True, blank=True) gender = models.CharField(max_length=6, choices=( ("male", u"男"), ("female", u"女")), verbose_name=u"性别") address = models.CharField(max_length=100, default=u"", null=True, blank=True, verbose_name=u"地址") mobile = models.CharField(max_length=11, null=True, blank=True, verbose_name=u"手机号码") avatar = models.ImageField(upload_to="image/%Y/%m", default=u"image/default.png", verbose_name=u"用户头像") class Meta: verbose_name = u"用户信息表" verbose_name_plural = verbose_name # db_table = # ordering = def __unicode__(self): return self.username # model中可定义方法动态获取数据,使用时相当于所定义的字段,如以下获取未读消息数量: def get_unread_nums(self): from operation.models import UserMessage return UserMessage.objects.filter(id=self.id, has_read=False).count() # 如需在后台中显示,设置显示名称的方法如下 get_unread_nums.short_description = "未读消息数量" # 扩展:使url在后台中以锚文本形式显示 def go_to(self): from django.utils.safestring import mark_safe return mark_safe("<a href='"+self.url+"' target='_blank'>点此访问</a>")
settings.py
AUTH_USER_MODEL = "users.UserProfile"
admin.py
需要进行注册
from .models import UserProfile class UserProfileAdmin(admin.ModelAdmin): pass admin.site.register(UserProfile, UserProfileAdmin)
如果使用的是xadmin的话,常规需通过如下方式注册才不会报错
adminx.py
from xadmin.plugins.auth import UserAdmin from .models import UserProfile class UserProfileAdmin(UserAdmin): pass # 在此处拷贝UserAdmin中的get_form_layout可进行布局自定义 xadmin.site.register(UserProfile, UserProfileAdmin) # 卸载原始User from django.contrib.auth.models import User xadmin.site.unregister(User)
但由于xadmin当前版本的bug进行上述操作会导致密码无法修改,解决的方法是注释掉前面的register和unregister部分,然后在xadmin源码的plugins/auth.py的包引用结束处添加
from django.contrib.auth import get_user_model User = get_user_model()
并将auth.py中的site.register_view(r’^auth/user/(.+)/password/$’,修改为
site.register_view(r'^users/userprofile/(.+)/password/$'
xadmin中的常用配置
# adminx.py(更多内容可查看xadmin/plugins下的源码) list_display # 设置默认显示字段 search_fields # 设置可搜索字段 list_filter # 设置可过滤字段 model_icon # 设置左侧导航中显示的icon list_editable # 设置行内可编辑字段 readonly_fields # 设置字段仅可为读 exclude # 取消字段在后台表单中的显示 refresh_times = [3, 5] # 设置在后台自行选择自动刷新间隔 relfield_style = 'fk-ajax' #外键指向字段内容过多时默认不下拉通过搜索显示 # 注:readonly_fields和exclude两者是冲突的,只能设置一个 # 设置顶部可选主题 class BaseSetting(object): enable_themes = True use_bootswatch = True # 设置头部标题,底部信息,左侧导航样式 class GlobalSettings(object): site_title = "xx后台管理系统" site_footer = "xx网" menu_style = "accordion" xadmin.site.register(views.BaseAdminView, BaseSetting) xadmin.site.register(views.CommAdminView, GlobalSettings) # 重载get_form_layout修改后台表单样式 # apps.py # 添加verbose_name修改左侧导航显示名称 class UsersConfig(AppConfig): name = 'users' verbose_name = "用户信息" # __init.py__:使上面的名称配置生效,也可不配置这里,在INSTALLED_APPS的引入直接写users.apps.UsersConfig default_app_config = "users.apps.UsersConfig" # 对于同一张表过滤在后台中分开显示 # 1.model.py中的设置:继承原model,重点是配置proxy = true class BannerCourse(Course): class Meta: verbose_name = "轮播课程" verbose_name_plural = verbose_name proxy = True # 2. adminx.py中的设置, 重点是重载queryset方法 class BannerCourseAdmin(object): ... def queryset(self): qs = super(BannerCourseAdmin, self).queryset() qs = qs.filter(is_banner=True) return qs # 以下部分为设置在保存和新增时自己的逻辑,只需添加save_models方法 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() # inline设置 # 1.对包含外键的model进行设置,其中的Lesson为类名 class LessonInline(object): model = Lesson extra = 0 # 添加inlines,此时在后台中添加课程的同时便可以添加具体章节了 class CourseAdmin(object): ... inlines = [LessonInline]
用户登录重写
# 重写支持用户名和邮箱登录 from django.contrib.auth.backends import ModelBackend from django.db.models import Q class CustomBackend(ModelBackend): def authenticate(self, request, 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', ) # 登录逻辑 user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) ...
html模板
xxx|default_if_none:''
更多:
add, addslashes, capfirst, center, cut, date, default, default_if_none, dictsort, dictsortreversed, divisibleby, escape, escapejs, filesizeformat, first, floatformat, force_escape, get_digit, iriencode, join, last, length, length_is, linebreaks, linebreaksbr, linenumbers, ljust, lower, make_list, phone2numeric, pluralize, pprint, random, rjust, safe, safeseq, slice, slugify, stringformat, striptags, time, timesince, timeuntil, title, truncatechars, truncatechars_html, truncatewords, truncatewords_html, unordered_list, upper, urlencode, urlize, urlizetrunc, wordcount, wordwrap, yesno
Xadmin集成ueditor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# settings.py INSTALLED_APPS = [ ... 'DjangoUeditor', ] # models.py, 添加方法和其它Field类似,更多详情参见https://github.com/zhangfisher/DjangoUeditor from DjangoUeditor.models import UEditorField detail = UEditorField(verbose_name="课程详情",width=600, height=300, imagePath="course/ueditor", filePath="course/ueditor", upload_settings={"imageMaxSize":1204000},) # adminx.py style_fields = {"detail": "ueditor"} # xadmin/plugins下新建文件ueditor.py 用于添加插入相关JS文件,以及在get_field_style中添加style判断,名称与adminx.py中相对应 import xadmin from xadmin.views import BaseAdminPlugin, CreateAdminView, ModelFormAdminView, UpdateAdminView 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)} return attrs def block_extrahead(self, context, nodes): js = '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL + "ueditor/ueditor.config.js") #自己的静态目录 js += '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL + "ueditor/ueditor.all.min.js") #自己的静态目录 nodes.append(js) xadmin.site.register_plugin(UeditorPlugin, UpdateAdminView) xadmin.site.register_plugin(UeditorPlugin, CreateAdminView) # xadmin/plugins/__init__.py PLUGINS = ( ... 'ueditor' ) # 前台模板调用, 取消转义以正常显示 {% autoescape off %} {{ course.detail }} {% endautoescape %} |