Initial commit

This commit is contained in:
柳辉
2017-07-05 21:09:36 +08:00
commit cf92ee1e3b
465 changed files with 86467 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="settings.py" />
<option name="manageScript" value="manage.py" />
<option name="environment" value="&lt;map/&gt;" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/apps" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Python 3.5.3 virtualenv at ~/Envs/dgblog" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
+5
View File
@@ -0,0 +1,5 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
</profile>
</component>
+7
View File
@@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="useProjectProfile" value="false" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+35
View File
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
</expanded-state>
<selected-state>
<State>
<id>AngularJS</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5.3 virtualenv at ~/Envs/dgblog" project-jdk-type="Python SDK" />
<component name="masterDetails">
<states>
<state key="ScopeChooserConfigurable.UI">
<settings>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/djangoblog.iml" filepath="$PROJECT_DIR$/.idea/djangoblog.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+1
View File
@@ -0,0 +1 @@
__author__ = 'liuhui'
+1
View File
@@ -0,0 +1 @@
default_app_config = 'blog.apps.BlogConfig'
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+34
View File
@@ -0,0 +1,34 @@
__author__ = 'liuhui'
import xadmin
from .models import Article, Category, Link
class ArticleAdmin(object):
list_display = ['author', 'category', 'tags', 'title', 'article_from', 'reading_num', 'comment_num', 'like_num', 'is_top', 'rank', 'status', 'create_time', 'update_time']
search_fields = ['author', 'category', 'tags', 'title', 'summary', 'article_from', 'content', 'reading_num', 'comment_num', 'like_num', 'is_top', 'rank', 'status']
list_filter = ['author__username', 'category__name', 'tags', 'summary', 'article_from', 'content', 'reading_num', 'comment_num', 'like_num', 'is_top', 'rank', 'status', 'create_time', 'update_time']
readonly_fields = []
style_fields = {'content': 'ueditor'}
relfield_style = 'fk-ajax'
class CategoryAdmin(object):
list_display = ['name', 'rank', 'create_time', 'update_time']
search_fields = ['name', 'rank']
list_filter = ['name', 'rank', 'create_time', 'update_time']
class LinkAdmin(object):
list_display = ['name', 'url', 'rank', 'create_time', 'update_time']
search_fields = ['name', 'url', 'rank']
list_filter = ['name', 'url', 'rank', 'create_time', 'update_time']
xadmin.site.register(Article, ArticleAdmin)
xadmin.site.register(Category, CategoryAdmin)
xadmin.site.register(Link, LinkAdmin)
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class BlogConfig(AppConfig):
name = 'blog'
verbose_name = '博客管理'
+72
View File
@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-04 02:41
from __future__ import unicode_literals
import DjangoUeditor.models
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Article',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50, verbose_name='标题')),
('alias', models.CharField(blank=True, max_length=100, null=True, verbose_name='英文名')),
('article_from', models.IntegerField(choices=[(0, '原创'), (1, '转载')], default=0, verbose_name='文章来源')),
('summary', models.TextField(verbose_name='摘要')),
('tags', models.CharField(blank=True, max_length=100, null=True)),
('content', DjangoUeditor.models.UEditorField(default='', verbose_name='正文')),
('reading_num', models.IntegerField(default=0, verbose_name='阅读量')),
('comment_num', models.IntegerField(default=0, verbose_name='评论数')),
('like_num', models.IntegerField(default=0, verbose_name='点赞数')),
('is_top', models.BooleanField(default=False, verbose_name='是否置顶')),
('rank', models.IntegerField(default=0, verbose_name='排序')),
('status', models.IntegerField(choices=[(0, '发表'), (1, '草稿'), (2, '丢弃')], default=0, verbose_name='文章状态')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, null=True, verbose_name='修改时间')),
],
options={
'verbose_name_plural': '文章',
'verbose_name': '文章',
},
),
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=40, verbose_name='类型名称')),
('rank', models.IntegerField(default=0, verbose_name='排序')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, null=True, verbose_name='修改时间')),
],
options={
'verbose_name_plural': '文章类型',
'verbose_name': '文章类型',
'ordering': ['rank', '-create_time'],
},
),
migrations.CreateModel(
name='Link',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=40, verbose_name='链接名')),
('url', models.URLField(max_length=40, verbose_name='链接地址')),
('rank', models.IntegerField(default=0, verbose_name='排序')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, null=True, verbose_name='修改时间')),
],
options={
'verbose_name_plural': '友情链接',
'verbose_name': '友情链接',
},
),
]
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-04 02:41
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('blog', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='article',
name='author',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者'),
),
migrations.AddField(
model_name='article',
name='category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.Category', verbose_name='类型'),
),
]
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-05 02:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('blog', '0002_auto_20170704_1041'),
]
operations = [
migrations.RenameField(
model_name='article',
old_name='alias',
new_name='en_title',
),
migrations.AlterField(
model_name='article',
name='tags',
field=models.CharField(blank=True, help_text='用逗号分隔', max_length=100, null=True, verbose_name='标签'),
),
]
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-05 07:45
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('blog', '0003_auto_20170705_1056'),
]
operations = [
migrations.RemoveField(
model_name='article',
name='en_title',
),
]
View File
+98
View File
@@ -0,0 +1,98 @@
from datetime import datetime
from django.db import models
from djangoblog import settings
from django.utils import timezone
from DjangoUeditor.models import UEditorField
# Create your models here.
STATUS = {
0: u'发表',
1: u'草稿',
2: u'丢弃',
}
ARTICLE_FROM = {
0: u'原创',
1: u'转载',
}
class Category(models.Model):
name = models.CharField(max_length=40, verbose_name=u'类型名称')
rank = models.IntegerField(default=0,verbose_name=u'排序')
create_time = models.DateTimeField(verbose_name=u'创建时间',default=timezone.now)
update_time = models.DateTimeField(verbose_name=u'修改时间',blank=True,null=True)
class Meta:
verbose_name = u'文章类型'
verbose_name_plural = verbose_name
ordering = ['rank','-create_time']
def __str__(self):
return self.name
class Article(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL,verbose_name=u'作者')
category = models.ForeignKey(Category,verbose_name=u'类型')
title = models.CharField(max_length=50,verbose_name=u'标题')
#en_title = models.CharField(max_length=100, blank=True, null=True, verbose_name=u'英文名')
article_from = models.IntegerField(default=0,choices=ARTICLE_FROM.items(),verbose_name=u'文章来源')
summary = models.TextField(verbose_name=u'摘要')
tags = models.CharField(max_length=100, null=True, blank=True, verbose_name=u'标签', help_text=u'用逗号分隔')
content = UEditorField(verbose_name=u'正文', toolbars='full', width='600', height='300', imagePath='article/ueditor/',filePath='article/ueditor',default='')
reading_num = models.IntegerField(default=0,verbose_name=u'阅读量')
comment_num = models.IntegerField(default=0,verbose_name=u'评论数')
like_num = models.IntegerField(default=0,verbose_name=u'点赞数')
is_top = models.BooleanField(default=False,verbose_name=u'是否置顶')
rank = models.IntegerField(default=0,verbose_name=u'排序')
status = models.IntegerField(default=0,choices=STATUS.items(),verbose_name=u'文章状态')
create_time = models.DateTimeField(default=timezone.now, verbose_name=u'创建时间')
update_time = models.DateTimeField(verbose_name=u'修改时间', blank=True, null=True)
class Meta:
verbose_name = u'文章'
verbose_name_plural = verbose_name
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('article-view', args=(self.en_title,))
def get_tags(self):
tags_list = self.tags.split(',')
while '' in tags_list:
tags_list.remove('')
tags_list = tags_list[0:3]
return tags_list
def get_category(self):
return self.category
def __str__(self):
return self.title
class Link(models.Model):
name = models.CharField(max_length=40, verbose_name=u'链接名')
url = models.URLField(max_length=40, verbose_name=u'链接地址')
rank = models.IntegerField(default=0, verbose_name=u'排序')
create_time = models.DateTimeField(default=timezone.now, verbose_name=u'创建时间')
update_time = models.DateTimeField(verbose_name=u'修改时间', blank=True, null=True)
class Meta:
verbose_name = u'友情链接'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+11
View File
@@ -0,0 +1,11 @@
__author__ = 'liuhui'
from django.conf.urls import url, include
from blog.views import IndexView, ArticleDetailView, CategoryView, TagView
urlpatterns = [
url(r'^$', IndexView.as_view(), name="index-view"),
url(r'^article/(?P<article_id>\d+)/$', ArticleDetailView.as_view(), name='article-view'),
url(r'^category/(?P<category_id>\d+)/$', CategoryView.as_view(), name='category-view'),
url(r'^tag/(?P<tag>\d+)/$', TagView.as_view(), name='tag-view'),
]
+91
View File
@@ -0,0 +1,91 @@
from django.shortcuts import render
from django.http import HttpResponse, Http404
from django.views.generic import ListView, TemplateView, View, DetailView
from blog.models import Article, Category, Link
from comments.models import Comment
from users.models import UserProfile
from djangoblog import settings
from django.db.models import Q
from django.core.cache import caches
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
cache = caches['default']
# Create your views here.
class BaseMixin(object):
def get_context_data(self, *args, **kwargs):
context = super(BaseMixin, self).get_context_data(**kwargs)
context['category_list'] = Category.objects.all()[:10]
context['hot_article_list'] = Article.objects.order_by("-reading_num")[:10]
context['new_comment_list'] = Comment.objects.order_by("-create_time")[:5]
context['hot_user_list'] = UserProfile.objects.order_by("-topic_num")[:5]
context['link_list'] = Link.objects.order_by('-create_time')
colors = ['primary', 'success', 'info', 'warning', 'danger']
for index, link in enumerate(context['link_list']):
link.color = colors[index % len(colors)]
return context
class IndexView(BaseMixin, ListView):
template_name = 'blog/index.html'
context_object_name = 'article_list'
paginate_by = settings.PAGE_NUM
def get_queryset(self):
article_list = Article.objects.filter(status=0).order_by('-create_time')
return article_list
def get_context_data(self, **kwargs):
kwargs['category_list'] = Category.objects.all().order_by('rank')
return super(IndexView, self).get_context_data(**kwargs)
class ArticleDetailView(BaseMixin, DetailView):
model = Article
template_name = 'blog/article.html'
context_object_name = 'article'
pk_url_kwarg = 'article_id'
def get_object(self, queryset=None):
obj = super(ArticleDetailView, self).get_object()
#文章点击数 + 1
obj.reading_num += 1
obj.save()
return obj
def get_context_data(self, **kwargs):
return super(ArticleDetailView, self).get_context_data(**kwargs)
class CategoryView(BaseMixin, ListView):
template_name = 'blog/index.html'
context_object_name = "article_list"
paginate_by = settings.PAGE_NUM
def get_queryset(self):
article_list = Article.objects.filter(category=self.kwargs['category_id'], status=0).order_by('-create_time')
return article_list
def get_context_data(self, **kwargs):
return super(CategoryView, self).get_context_data(**kwargs)
class TagView(BaseMixin, ListView):
template_name = 'blog/index.html'
context_object_name = 'article_list'
paginate_by = settings.PAGE_NUM
def get_queryset(self):
tag = self.kwargs.get('tag', '')
article_list = Article.objects.only('tags').filter(tags__icontains=self.kwargs['tag'], status=0)
return article_list
def get_context_data(self, **kwargs):
return super(TagView, self).get_context_data(**kwargs)
+1
View File
@@ -0,0 +1 @@
default_app_config = 'comments.apps.CommentsConfig'
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+14
View File
@@ -0,0 +1,14 @@
__author__ = 'liuhui'
import xadmin
from .models import Comment
class CommentAdmin(object):
list_display = ['user', 'article', 'text', 'create_time', 'parentcomment']
search_fields = ['user', 'article', 'text', 'parentcomment']
list_filter = ['user__username', 'article__title', 'text', 'create_time', 'parentcomment']
field = ['user__username', 'article_title']
xadmin.site.register(Comment, CommentAdmin)
+7
View File
@@ -0,0 +1,7 @@
from django.apps import AppConfig
class CommentsConfig(AppConfig):
name = 'comments'
verbose_name = '评论信息'
+37
View File
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-04 02:41
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('blog', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Comment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(verbose_name='评论')),
('is_removed', models.BooleanField(default=False)),
('likes_count', models.PositiveIntegerField(default=0, verbose_name='点赞数')),
('create_time', models.DateTimeField(default=datetime.datetime.now, verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, null=True, verbose_name='修改时间')),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.Article', verbose_name='文章')),
('parentcomment', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.Comment', verbose_name='父评论')),
],
options={
'verbose_name_plural': '评论',
'verbose_name': '评论',
'ordering': ['-create_time'],
},
),
]
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-04 02:41
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('comments', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='comment',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户'),
),
]
+25
View File
@@ -0,0 +1,25 @@
from django.db import models
from django.conf import settings
from blog.models import Article
from datetime import datetime
# Create your models here.
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,verbose_name=u'用户')
article = models.ForeignKey(Article,verbose_name=u'文章')
text = models.TextField(verbose_name=u'评论')
is_removed = models.BooleanField(default=False)
parentcomment = models.ForeignKey('self',default=None,blank=True,null=True,verbose_name=u'父评论')
likes_count = models.PositiveIntegerField(default=0,verbose_name=u'点赞数')
create_time = models.DateTimeField(verbose_name=u'创建时间', default=datetime.now)
update_time = models.DateTimeField(verbose_name=u'修改时间', blank=True, null=True)
class Meta:
verbose_name = u'评论'
verbose_name_plural = verbose_name
ordering = ['-create_time']
def __str__(self):
return self.article.title
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+9
View File
@@ -0,0 +1,9 @@
__author__ = 'liuhui'
from django.conf.urls import url, include
urlpatterns = [
]
+3
View File
@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.
View File
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class SearchConfig(AppConfig):
name = 'apps.search'
View File
+3
View File
@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+4
View File
@@ -0,0 +1,4 @@
from django.shortcuts import render
from django.conf import settings
from django.db.models import Q
# Create your views here.
+1
View File
@@ -0,0 +1 @@
default_app_config = "users.apps.UsersConfig"
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+44
View File
@@ -0,0 +1,44 @@
__author__ = 'liuhui'
import xadmin
from xadmin import views
from .models import Banner, Follower, EmailVerified
class BaseSettings(object):
enable_themes = True
use_bootswatch = True
class GlobalSettings(object):
site_title = "博客后台管理"
site_footer = "开发者在线"
menu_style = 'accordion'
class FollowerAdmin(object):
list_display = ['user_a', 'user_b', 'create_time']
search_fields = ['user_a', 'user_b']
list_filter = ['user_a__username', 'user_b__username', 'create_time']
class BannerAdmin(object):
list_display = ['title', 'image', 'url', 'rank', 'create_time']
search_fields = ['title', 'image', 'url', 'rank']
list_filter = ['title', 'image', 'url', 'rank', 'create_time']
class EmailVerifiedAdmin(object):
list_display = ['user', 'token', 'timestamp']
search_fields = ['user', 'token']
list_filter = ['user__username', 'token', 'timestamp']
xadmin.site.register(views.BaseAdminView, BaseSettings)
xadmin.site.register(views.CommAdminView, GlobalSettings)
xadmin.site.register(Follower, FollowerAdmin)
xadmin.site.register(Banner, BannerAdmin)
xadmin.site.register(EmailVerified, EmailVerifiedAdmin)
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
verbose_name = '用户信息'
+36
View File
@@ -0,0 +1,36 @@
__author__ = 'liuhui'
from django import forms
from django.contrib import auth
from .models import UserProfile
class LoginForm(forms.Form):
username = forms.CharField(label=u'用户名', widget=forms.TextInput(attrs={'placeholder': '用户名或邮箱', 'required': 'required'}), max_length=32, error_messages={'required': u'用户名或邮箱不能为空!'})
password = forms.CharField(label=u'密码', widget=forms.PasswordInput(attrs={'placeholder': '密码', 'required': 'required'}), max_length=16, error_messages={'required': u'密码不能为空!'})
def __init__(self, request=None, *args, **kwargs):
self.request = request
self.user_cache = None
super(LoginForm, self).__init__(*args, **kwargs)
def clean_password(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = auth.authenticate(username=username, password=password)
if self.user_cache is None:
raise forms.ValidationError(u'用户名或密码不匹配')
return self.cleaned_data
def get_user(self):
return self.user_cache
class RegisterForm(forms.Form):
username = forms.CharField()
email = forms.EmailField()
password = forms.CharField()
res_password = forms.CharField()
+101
View File
@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-07-04 02:41
from __future__ import unicode_literals
from django.conf import settings
import django.contrib.auth.models
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0008_alter_user_username_max_length'),
]
operations = [
migrations.CreateModel(
name='UserProfile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('username', models.CharField(max_length=32, unique=True, verbose_name='用户名')),
('email', models.EmailField(max_length=64, unique=True, verbose_name='邮箱')),
('password', models.CharField(max_length=128, verbose_name='密码')),
('profile', models.TextField(blank=True, max_length=200, null=True, verbose_name='简介')),
('image', models.ImageField(default='/static/images/user/default.jpg', max_length=200, upload_to='user_images/%Y/%m/%d', verbose_name='用户头像')),
('au', models.IntegerField(default=0, verbose_name='用户活跃度')),
('topic_num', models.IntegerField(default=0, verbose_name='文章数')),
('visit_num', models.IntegerField(default=0, verbose_name='访问量')),
('comment_num', models.IntegerField(default=0, verbose_name='总评论数')),
('email_verified', models.BooleanField(default=False, verbose_name='邮箱是否验证')),
('is_active', models.BooleanField(default=True)),
('create_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, null=True, verbose_name='修改时间')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name_plural': '用户',
'verbose_name': '用户',
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='Banner',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100, verbose_name='标题')),
('image', models.ImageField(upload_to='banner_images/%Y/%m/%d', verbose_name='轮播图')),
('url', models.URLField(verbose_name='访问地址')),
('rank', models.IntegerField(default=100, verbose_name='顺序')),
('create_time', models.DateField(default=django.utils.timezone.now, verbose_name='创建时间')),
('update_time', models.DateTimeField(blank=True, null=True, verbose_name='修改时间')),
],
options={
'verbose_name_plural': '轮播图',
'verbose_name': '轮播图',
},
),
migrations.CreateModel(
name='EmailVerified',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.CharField(default=None, max_length=32, verbose_name='Email 验证 token')),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL, verbose_name='用户')),
],
options={
'verbose_name_plural': '邮箱验证',
'verbose_name': '邮箱验证',
},
),
migrations.CreateModel(
name='Follower',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('user_a', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_a', to=settings.AUTH_USER_MODEL, verbose_name='关注者')),
('user_b', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_b', to=settings.AUTH_USER_MODEL, verbose_name='被关注者')),
],
options={
'verbose_name_plural': '用户关注',
'verbose_name': '用户关注',
},
),
migrations.AlterUniqueTogether(
name='follower',
unique_together=set([('user_a', 'user_b')]),
),
]
View File
+157
View File
@@ -0,0 +1,157 @@
import hashlib
import random
import string
from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.conf import settings
from django.utils import timezone
from datetime import datetime
SALT = getattr(settings, "EMAIL_TOKEN_SALT", "djangoblog")
# Create your models here.
class UserManage(BaseUserManager):
def create_user(self, username, email, password=None):
"""
Creates and saves a User
"""
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError("Users must have an username")
now = timezone.now()
user = self.model(username=username,
email=self.normalize_email(email),
create_time=now,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password=None):
"""
Creates and saves a superuser
"""
user = self.create_user(username,
email,
password,
)
user.is_admin = True
user.save(using=self._db)
return user
class UserProfile(AbstractUser):
username = models.CharField(max_length=32,verbose_name=u'用户名',unique=True)
email = models.EmailField(max_length=64,verbose_name=u'邮箱',unique=True)
password = models.CharField(max_length=128,verbose_name=u'密码')
profile = models.TextField(max_length=200,verbose_name=u'简介',blank=True,null=True)
image = models.ImageField(max_length=200,upload_to='user_images/%Y/%m/%d' ,default="/static/images/user/default.jpg", verbose_name=u'用户头像')
au = models.IntegerField(default=0, verbose_name=u'用户活跃度')
topic_num = models.IntegerField(default=0,verbose_name=u'文章数')
visit_num = models.IntegerField(default=0,verbose_name=u'访问量')
comment_num = models.IntegerField(default=0,verbose_name=u'总评论数')
email_verified = models.BooleanField(default=False, verbose_name=u'邮箱是否验证')
is_active = models.BooleanField(default=True)
create_time = models.DateTimeField(verbose_name=u'创建时间',default=timezone.now)
update_time = models.DateTimeField(verbose_name=u'修改时间', blank=True, null=True)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
verbose_name = u'用户'
verbose_name_plural = verbose_name
def is_email_verified(self):
return self.email_verified
def get_username(self):
return self.username
def get_email(self):
return self.email
def get_full_name(self):
return self.email
def get_short_name(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
def calculate_au(self):
self.au = self.topic_num * 5 + self.visit_num * 1 + self.comment_num * 1
return self.au
def __str__(self):
return self.username
class Banner(models.Model):
title = models.CharField(max_length=100, verbose_name=u'标题')
image = models.ImageField(upload_to='banner_images/%Y/%m/%d', max_length=100, verbose_name=u'轮播图')
url = models.URLField(max_length=200, verbose_name=u'访问地址')
rank = models.IntegerField(default=100, verbose_name=u'顺序')
create_time = models.DateField(default=timezone.now, verbose_name='创建时间')
update_time = models.DateTimeField(verbose_name=u'修改时间', blank=True, null=True)
class Meta:
verbose_name = '轮播图'
verbose_name_plural = verbose_name
def __str__(self):
return self.title
class Follower(models.Model):
user_a = models.ForeignKey(UserProfile, related_name="user_a", verbose_name=u'关注者')
user_b = models.ForeignKey(UserProfile, related_name="user_b", verbose_name=u'被关注者')
create_time = models.DateTimeField(default=timezone.now, verbose_name=u'创建时间')
class Meta:
unique_together = ('user_a', 'user_b')
verbose_name = u'用户关注'
verbose_name_plural = verbose_name
def __str__(self):
return "%s following %s" % (self.user_a, self.user_b)
class EmailVerified(models.Model):
user = models.OneToOneField(UserProfile, related_name='user', verbose_name=u'用户')
token = models.CharField(max_length=32, default=None, verbose_name=u"Email 验证 token")
timestamp = models.DateTimeField(default=timezone.now)
class Meta:
verbose_name = u'邮箱验证'
verbose_name_plural = verbose_name
def __str__(self):
return "%s@%s" % (self.user, self.token)
def generate_token(self):
year = self.timestamp.year
month = self.timestamp.month
day = self.timestamp.day
date = "%s-%s-%s" % (year, month, day)
token = hashlib.md5(str(self.user.id) + self.user.username + self.ran_str() + date).hexdigest()
def ran_str(self):
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
return salt + SALT
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+12
View File
@@ -0,0 +1,12 @@
__author__ = 'liuhui'
from django.conf.urls import url, include
from users.views import LoginView
from users import views
urlpatterns = [
url(r'^login/$', LoginView.as_view(), name='login'),
url(r'^logout/$', views.logout, name='logout'),
]
+48
View File
@@ -0,0 +1,48 @@
from django.shortcuts import render, redirect
from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from django.contrib import auth
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST
from django.http.response import HttpResponseRedirect
from django.views.decorators.csrf import csrf_protect
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.contrib.auth.decorators import login_required
from django.core.cache import cache
from django.contrib import messages
from django.utils import timezone
from .forms import LoginForm
from .models import UserProfile
import datetime
import re
import json
import random
# Create your views here.
class LoginView(View):
def get(self, request):
return render(request, 'users/login.html')
def post(self, request):
if request.method == "POST":
login_form = LoginForm(request.POST)
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
auth_login(request, user)
return HttpResponsePermanentRedirect(reverse('index-view'))
return render(request, 'users/login.html', {'msg': '用户名或密码错误'})
return render(request, 'users/login.html', {'form_errors': login_form.errors})
def logout(request):
auth_logout(request)
return HttpResponseRedirect(reverse("index-view"))
+14
View File
@@ -0,0 +1,14 @@
[main]
host = https://www.transifex.com
[xadmin-core.django]
file_filter = locale/<lang>/LC_MESSAGES/django.po
source_file = locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO
[xadmin-core.djangojs]
file_filter = locale/<lang>/LC_MESSAGES/djangojs.po
source_file = locale/en/LC_MESSAGES/djangojs.po
source_lang = en
type = PO
+68
View File
@@ -0,0 +1,68 @@
VERSION = (0,6,0)
from xadmin.sites import AdminSite, site
class Settings(object):
pass
def autodiscover():
"""
Auto-discover INSTALLED_APPS admin.py modules and fail silently when
not present. This forces an import on them to register any admin bits they
may want.
"""
from importlib import import_module
from django.conf import settings
from django.utils.module_loading import module_has_submodule
setattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap3')
setattr(settings, 'CRISPY_CLASS_CONVERTERS', {
"textinput": "textinput textInput form-control",
"fileinput": "fileinput fileUpload form-control",
"passwordinput": "textinput textInput form-control",
})
from xadmin.views import register_builtin_views
register_builtin_views(site)
# load xadmin settings from XADMIN_CONF module
try:
xadmin_conf = getattr(settings, 'XADMIN_CONF', 'xadmin_conf.py')
conf_mod = import_module(xadmin_conf)
except Exception:
conf_mod = None
if conf_mod:
for key in dir(conf_mod):
setting = getattr(conf_mod, key)
try:
if issubclass(setting, Settings):
site.register_settings(setting.__name__, setting)
except Exception:
pass
from xadmin.plugins import register_builtin_plugins
register_builtin_plugins(site)
for app in settings.INSTALLED_APPS:
mod = import_module(app)
# Attempt to import the app's admin module.
try:
before_import_registry = site.copy_registry()
import_module('%s.adminx' % app)
except:
# Reset the model registry to the state before the last import as
# this import will have to reoccur on the next request and this
# could raise NotRegistered and AlreadyRegistered exceptions
# (see #8245).
site.restore_registry(before_import_registry)
# Decide whether to bubble up this error. If the app just
# doesn't have an admin module, we can ignore the error
# attempting to import it, otherwise we want it to bubble up.
if module_has_submodule(mod, 'adminx'):
raise
default_app_config = 'xadmin.apps.XAdminConfig'
+32
View File
@@ -0,0 +1,32 @@
from __future__ import absolute_import
import xadmin
from .models import UserSettings, Log
from xadmin.layout import *
from django.utils.translation import ugettext_lazy as _, ugettext
class UserSettingsAdmin(object):
model_icon = 'fa fa-cog'
hidden_menu = True
xadmin.site.register(UserSettings, UserSettingsAdmin)
class LogAdmin(object):
def link(self, instance):
if instance.content_type and instance.object_id and instance.action_flag != 'delete':
admin_url = self.get_admin_url('%s_%s_change' % (instance.content_type.app_label, instance.content_type.model),
instance.object_id)
return "<a href='%s'>%s</a>" % (admin_url, _('Admin Object'))
else:
return ''
link.short_description = ""
link.allow_tags = True
link.is_column = False
list_display = ('action_time', 'user', 'ip_addr', '__str__', 'link')
list_filter = ['user', 'action_time']
search_fields = ['ip_addr', 'message']
model_icon = 'fa fa-cog'
xadmin.site.register(Log, LogAdmin)
+15
View File
@@ -0,0 +1,15 @@
from django.apps import AppConfig
from django.core import checks
from django.utils.translation import ugettext_lazy as _
import xadmin
class XAdminConfig(AppConfig):
"""Simple AppConfig which does not do automatic discovery."""
name = 'xadmin'
verbose_name = _("Administration")
def ready(self):
self.module.autodiscover()
setattr(xadmin,'site',xadmin.site)
+571
View File
@@ -0,0 +1,571 @@
from __future__ import absolute_import
from django.db import models
from django.core.exceptions import ImproperlyConfigured
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.template.loader import get_template
from django.template.context import Context
from django.utils import six
from django.utils.safestring import mark_safe
from django.utils.html import escape,format_html
from django.utils.text import Truncator
from django.core.cache import cache, caches
from xadmin.views.list import EMPTY_CHANGELIST_VALUE
from xadmin.util import is_related_field,is_related_field2
import datetime
FILTER_PREFIX = '_p_'
SEARCH_VAR = '_q_'
from .util import (get_model_from_relation,
reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value)
class BaseFilter(object):
title = None
template = 'xadmin/filters/list.html'
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
pass
def __init__(self, request, params, model, admin_view):
self.used_params = {}
self.request = request
self.params = params
self.model = model
self.admin_view = admin_view
if self.title is None:
raise ImproperlyConfigured(
"The filter '%s' does not specify "
"a 'title'." % self.__class__.__name__)
def query_string(self, new_params=None, remove=None):
return self.admin_view.get_query_string(new_params, remove)
def form_params(self):
arr = map(lambda k: FILTER_PREFIX + k, self.used_params.keys())
if six.PY3:
arr = list(arr)
return self.admin_view.get_form_params(remove=arr)
def has_output(self):
"""
Returns True if some choices would be output for this filter.
"""
raise NotImplementedError
@property
def is_used(self):
return len(self.used_params) > 0
def do_filte(self, queryset):
"""
Returns the filtered queryset.
"""
raise NotImplementedError
def get_context(self):
return {'title': self.title, 'spec': self, 'form_params': self.form_params()}
def __str__(self):
tpl = get_template(self.template)
return mark_safe(tpl.render(context=self.get_context()))
class FieldFilterManager(object):
_field_list_filters = []
_take_priority_index = 0
def register(self, list_filter_class, take_priority=False):
if take_priority:
# This is to allow overriding the default filters for certain types
# of fields with some custom filters. The first found in the list
# is used in priority.
self._field_list_filters.insert(
self._take_priority_index, list_filter_class)
self._take_priority_index += 1
else:
self._field_list_filters.append(list_filter_class)
return list_filter_class
def create(self, field, request, params, model, admin_view, field_path):
for list_filter_class in self._field_list_filters:
if not list_filter_class.test(field, request, params, model, admin_view, field_path):
continue
return list_filter_class(field, request, params,
model, admin_view, field_path=field_path)
manager = FieldFilterManager()
class FieldFilter(BaseFilter):
lookup_formats = {}
def __init__(self, field, request, params, model, admin_view, field_path):
self.field = field
self.field_path = field_path
self.title = getattr(field, 'verbose_name', field_path)
self.context_params = {}
super(FieldFilter, self).__init__(request, params, model, admin_view)
for name, format in self.lookup_formats.items():
p = format % field_path
self.context_params["%s_name" % name] = FILTER_PREFIX + p
if p in params:
value = prepare_lookup_value(p, params.pop(p))
self.used_params[p] = value
self.context_params["%s_val" % name] = value
else:
self.context_params["%s_val" % name] = ''
arr = map(
lambda kv: setattr(self, 'lookup_' + kv[0], kv[1]),
self.context_params.items()
)
if six.PY3:
list(arr)
def get_context(self):
context = super(FieldFilter, self).get_context()
context.update(self.context_params)
obj = map(lambda k: FILTER_PREFIX + k, self.used_params.keys())
if six.PY3:
obj = list(obj)
context['remove_url'] = self.query_string({}, obj)
return context
def has_output(self):
return True
def do_filte(self, queryset):
return queryset.filter(**self.used_params)
class ListFieldFilter(FieldFilter):
template = 'xadmin/filters/list.html'
def get_context(self):
context = super(ListFieldFilter, self).get_context()
context['choices'] = list(self.choices())
return context
@manager.register
class BooleanFieldListFilter(ListFieldFilter):
lookup_formats = {'exact': '%s__exact', 'isnull': '%s__isnull'}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return isinstance(field, (models.BooleanField, models.NullBooleanField))
def choices(self):
for lookup, title in (
('', _('All')),
('1', _('Yes')),
('0', _('No')),
):
yield {
'selected': (
self.lookup_exact_val == lookup
and not self.lookup_isnull_val
),
'query_string': self.query_string(
{self.lookup_exact_name: lookup},
[self.lookup_isnull_name],
),
'display': title,
}
if isinstance(self.field, models.NullBooleanField):
yield {
'selected': self.lookup_isnull_val == 'True',
'query_string': self.query_string(
{self.lookup_isnull_name: 'True'},
[self.lookup_exact_name],
),
'display': _('Unknown'),
}
@manager.register
class ChoicesFieldListFilter(ListFieldFilter):
lookup_formats = {'exact': '%s__exact'}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return bool(field.choices)
def choices(self):
yield {
'selected': self.lookup_exact_val is '',
'query_string': self.query_string({}, [self.lookup_exact_name]),
'display': _('All')
}
for lookup, title in self.field.flatchoices:
yield {
'selected': smart_text(lookup) == self.lookup_exact_val,
'query_string': self.query_string({self.lookup_exact_name: lookup}),
'display': title,
}
@manager.register
class TextFieldListFilter(FieldFilter):
template = 'xadmin/filters/char.html'
lookup_formats = {'in': '%s__in', 'search': '%s__contains'}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return (
isinstance(field, models.CharField)
and field.max_length > 20
or isinstance(field, models.TextField)
)
@manager.register
class NumberFieldListFilter(FieldFilter):
template = 'xadmin/filters/number.html'
lookup_formats = {'equal': '%s__exact', 'lt': '%s__lt', 'gt': '%s__gt',
'ne': '%s__ne', 'lte': '%s__lte', 'gte': '%s__gte',
}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return isinstance(field, (models.DecimalField, models.FloatField, models.IntegerField))
def do_filte(self, queryset):
params = self.used_params.copy()
ne_key = '%s__ne' % self.field_path
if ne_key in params:
queryset = queryset.exclude(
**{self.field_path: params.pop(ne_key)})
return queryset.filter(**params)
@manager.register
class DateFieldListFilter(ListFieldFilter):
template = 'xadmin/filters/date.html'
lookup_formats = {'since': '%s__gte', 'until': '%s__lt',
'year': '%s__year', 'month': '%s__month', 'day': '%s__day',
'isnull': '%s__isnull'}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return isinstance(field, models.DateField)
def __init__(self, field, request, params, model, admin_view, field_path):
self.field_generic = '%s__' % field_path
self.date_params = dict([(FILTER_PREFIX + k, v) for k, v in params.items()
if k.startswith(self.field_generic)])
super(DateFieldListFilter, self).__init__(
field, request, params, model, admin_view, field_path)
now = timezone.now()
# When time zone support is enabled, convert "now" to the user's time
# zone so Django's definition of "Today" matches what the user expects.
if now.tzinfo is not None:
current_tz = timezone.get_current_timezone()
now = now.astimezone(current_tz)
if hasattr(current_tz, 'normalize'):
# available for pytz time zones
now = current_tz.normalize(now)
if isinstance(field, models.DateTimeField):
today = now.replace(hour=0, minute=0, second=0, microsecond=0)
else: # field is a models.DateField
today = now.date()
tomorrow = today + datetime.timedelta(days=1)
self.links = (
(_('Any date'), {}),
(_('Has date'), {
self.lookup_isnull_name: False
}),
(_('Has no date'), {
self.lookup_isnull_name: 'True'
}),
(_('Today'), {
self.lookup_since_name: str(today),
self.lookup_until_name: str(tomorrow),
}),
(_('Past 7 days'), {
self.lookup_since_name: str(today - datetime.timedelta(days=7)),
self.lookup_until_name: str(tomorrow),
}),
(_('This month'), {
self.lookup_since_name: str(today.replace(day=1)),
self.lookup_until_name: str(tomorrow),
}),
(_('This year'), {
self.lookup_since_name: str(today.replace(month=1, day=1)),
self.lookup_until_name: str(tomorrow),
}),
)
def get_context(self):
context = super(DateFieldListFilter, self).get_context()
context['choice_selected'] = bool(self.lookup_year_val) or bool(self.lookup_month_val) \
or bool(self.lookup_day_val)
return context
def choices(self):
for title, param_dict in self.links:
yield {
'selected': self.date_params == param_dict,
'query_string': self.query_string(
param_dict, [FILTER_PREFIX + self.field_generic]),
'display': title,
}
@manager.register
class RelatedFieldSearchFilter(FieldFilter):
template = 'xadmin/filters/fk_search.html'
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
if not is_related_field2(field):
return False
related_modeladmin = admin_view.admin_site._registry.get(
get_model_from_relation(field))
return related_modeladmin and getattr(related_modeladmin, 'relfield_style', None) in ('fk-ajax', 'fk-select')
def __init__(self, field, request, params, model, model_admin, field_path):
other_model = get_model_from_relation(field)
if hasattr(field, 'rel'):
rel_name = field.rel.get_related_field().name
else:
rel_name = other_model._meta.pk.name
self.lookup_formats = {'in': '%%s__%s__in' % rel_name,'exact': '%%s__%s__exact' % rel_name}
super(RelatedFieldSearchFilter, self).__init__(
field, request, params, model, model_admin, field_path)
related_modeladmin = self.admin_view.admin_site._registry.get(other_model)
self.relfield_style = related_modeladmin.relfield_style
if hasattr(field, 'verbose_name'):
self.lookup_title = field.verbose_name
else:
self.lookup_title = other_model._meta.verbose_name
self.title = self.lookup_title
self.search_url = model_admin.get_admin_url('%s_%s_changelist' % (
other_model._meta.app_label, other_model._meta.model_name))
self.label = self.label_for_value(other_model, rel_name, self.lookup_exact_val) if self.lookup_exact_val else ""
self.choices = '?'
if field.rel.limit_choices_to:
for i in list(field.rel.limit_choices_to):
self.choices += "&_p_%s=%s" % (i, field.rel.limit_choices_to[i])
self.choices = format_html(self.choices)
def label_for_value(self, other_model, rel_name, value):
try:
obj = other_model._default_manager.get(**{rel_name: value})
return '%s' % escape(Truncator(obj).words(14, truncate='...'))
except (ValueError, other_model.DoesNotExist):
return ""
def get_context(self):
context = super(RelatedFieldSearchFilter, self).get_context()
context['search_url'] = self.search_url
context['label'] = self.label
context['choices'] = self.choices
context['relfield_style'] = self.relfield_style
return context
@manager.register
class RelatedFieldListFilter(ListFieldFilter):
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return is_related_field2(field)
def __init__(self, field, request, params, model, model_admin, field_path):
other_model = get_model_from_relation(field)
if hasattr(field, 'rel'):
rel_name = field.rel.get_related_field().name
else:
rel_name = other_model._meta.pk.name
self.lookup_formats = {'in': '%%s__%s__in' % rel_name,'exact': '%%s__%s__exact' %
rel_name, 'isnull': '%s__isnull'}
self.lookup_choices = field.get_choices(include_blank=False)
super(RelatedFieldListFilter, self).__init__(
field, request, params, model, model_admin, field_path)
if hasattr(field, 'verbose_name'):
self.lookup_title = field.verbose_name
else:
self.lookup_title = other_model._meta.verbose_name
self.title = self.lookup_title
def has_output(self):
if (is_related_field(self.field)
and self.field.field.null or hasattr(self.field, 'rel')
and self.field.null):
extra = 1
else:
extra = 0
return len(self.lookup_choices) + extra > 1
def expected_parameters(self):
return [self.lookup_kwarg, self.lookup_kwarg_isnull]
def choices(self):
yield {
'selected': self.lookup_exact_val == '' and not self.lookup_isnull_val,
'query_string': self.query_string({},
[self.lookup_exact_name, self.lookup_isnull_name]),
'display': _('All'),
}
for pk_val, val in self.lookup_choices:
yield {
'selected': self.lookup_exact_val == smart_text(pk_val),
'query_string': self.query_string({
self.lookup_exact_name: pk_val,
}, [self.lookup_isnull_name]),
'display': val,
}
if (is_related_field(self.field)
and self.field.field.null or hasattr(self.field, 'rel')
and self.field.null):
yield {
'selected': bool(self.lookup_isnull_val),
'query_string': self.query_string({
self.lookup_isnull_name: 'True',
}, [self.lookup_exact_name]),
'display': EMPTY_CHANGELIST_VALUE,
}
@manager.register
class MultiSelectFieldListFilter(ListFieldFilter):
""" Delegates the filter to the default filter and ors the results of each
Lists the distinct values of each field as a checkbox
Uses the default spec for each
"""
template = 'xadmin/filters/checklist.html'
lookup_formats = {'in': '%s__in'}
cache_config = {'enabled':False,'key':'quickfilter_%s','timeout':3600,'cache':'default'}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return True
def get_cached_choices(self):
if not self.cache_config['enabled']:
return None
c = caches(self.cache_config['cache'])
return c.get(self.cache_config['key']%self.field_path)
def set_cached_choices(self,choices):
if not self.cache_config['enabled']:
return
c = caches(self.cache_config['cache'])
return c.set(self.cache_config['key']%self.field_path,choices)
def __init__(self, field, request, params, model, model_admin, field_path,field_order_by=None,field_limit=None,sort_key=None,cache_config=None):
super(MultiSelectFieldListFilter,self).__init__(field, request, params, model, model_admin, field_path)
# Check for it in the cachce
if cache_config is not None and type(cache_config)==dict:
self.cache_config.update(cache_config)
if self.cache_config['enabled']:
self.field_path = field_path
choices = self.get_cached_choices()
if choices:
self.lookup_choices = choices
return
# Else rebuild it
queryset = self.admin_view.queryset().exclude(**{"%s__isnull"%field_path:True}).values_list(field_path, flat=True).distinct()
#queryset = self.admin_view.queryset().distinct(field_path).exclude(**{"%s__isnull"%field_path:True})
if field_order_by is not None:
# Do a subquery to order the distinct set
queryset = self.admin_view.queryset().filter(id__in=queryset).order_by(field_order_by)
if field_limit is not None and type(field_limit)==int and queryset.count()>field_limit:
queryset = queryset[:field_limit]
self.lookup_choices = [str(it) for it in queryset.values_list(field_path,flat=True) if str(it).strip()!=""]
if sort_key is not None:
self.lookup_choices = sorted(self.lookup_choices,key=sort_key)
if self.cache_config['enabled']:
self.set_cached_choices(self.lookup_choices)
def choices(self):
self.lookup_in_val = (type(self.lookup_in_val) in (tuple,list)) and self.lookup_in_val or list(self.lookup_in_val)
yield {
'selected': len(self.lookup_in_val) == 0,
'query_string': self.query_string({},[self.lookup_in_name]),
'display': _('All'),
}
for val in self.lookup_choices:
yield {
'selected': smart_text(val) in self.lookup_in_val,
'query_string': self.query_string({self.lookup_in_name: ",".join([val]+self.lookup_in_val),}),
'remove_query_string': self.query_string({self.lookup_in_name: ",".join([v for v in self.lookup_in_val if v != val]),}),
'display': val,
}
@manager.register
class AllValuesFieldListFilter(ListFieldFilter):
lookup_formats = {'exact': '%s__exact', 'isnull': '%s__isnull'}
@classmethod
def test(cls, field, request, params, model, admin_view, field_path):
return True
def __init__(self, field, request, params, model, admin_view, field_path):
parent_model, reverse_path = reverse_field_path(model, field_path)
queryset = parent_model._default_manager.all()
# optional feature: limit choices base on existing relationships
# queryset = queryset.complex_filter(
# {'%s__isnull' % reverse_path: False})
limit_choices_to = get_limit_choices_to_from_path(model, field_path)
queryset = queryset.filter(limit_choices_to)
self.lookup_choices = (queryset
.distinct()
.order_by(field.name)
.values_list(field.name, flat=True))
super(AllValuesFieldListFilter, self).__init__(
field, request, params, model, admin_view, field_path)
def choices(self):
yield {
'selected': (self.lookup_exact_val is '' and self.lookup_isnull_val is ''),
'query_string': self.query_string({}, [self.lookup_exact_name, self.lookup_isnull_name]),
'display': _('All'),
}
include_none = False
for val in self.lookup_choices:
if val is None:
include_none = True
continue
val = smart_text(val)
yield {
'selected': self.lookup_exact_val == val,
'query_string': self.query_string({self.lookup_exact_name: val},
[self.lookup_isnull_name]),
'display': val,
}
if include_none:
yield {
'selected': bool(self.lookup_isnull_val),
'query_string': self.query_string({self.lookup_isnull_name: 'True'},
[self.lookup_exact_name]),
'display': EMPTY_CHANGELIST_VALUE,
}
+47
View File
@@ -0,0 +1,47 @@
from django import forms
from django.contrib.auth import authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import ugettext_lazy, ugettext as _
from django.contrib.auth import get_user_model
ERROR_MESSAGE = ugettext_lazy("Please enter the correct username and password "
"for a staff account. Note that both fields are case-sensitive.")
class AdminAuthenticationForm(AuthenticationForm):
"""
A custom authentication form used in the admin app.
"""
this_is_the_login_form = forms.BooleanField(
widget=forms.HiddenInput, initial=1,
error_messages={'required': ugettext_lazy("Please log in again, because your session has expired.")})
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
message = ERROR_MESSAGE
if username and password:
self.user_cache = authenticate(
username=username, password=password)
if self.user_cache is None:
if u'@' in username:
User = get_user_model()
# Mistakenly entered e-mail address instead of username? Look it up.
try:
user = User.objects.get(email=username)
except (User.DoesNotExist, User.MultipleObjectsReturned):
# Nothing to do here, moving along.
pass
else:
if user.check_password(password):
message = _("Your e-mail address is not your username."
" Try '%s' instead.") % user.username
raise forms.ValidationError(message)
elif not self.user_cache.is_active or not self.user_cache.is_staff:
raise forms.ValidationError(message)
return self.cleaned_data
+113
View File
@@ -0,0 +1,113 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import *
from crispy_forms.bootstrap import *
from crispy_forms.utils import render_field, flatatt, TEMPLATE_PACK
from crispy_forms import layout
from crispy_forms import bootstrap
import math
class Fieldset(layout.Fieldset):
template = "xadmin/layout/fieldset.html"
def __init__(self, legend, *fields, **kwargs):
self.description = kwargs.pop('description', None)
self.collapsed = kwargs.pop('collapsed', None)
super(Fieldset, self).__init__(legend, *fields, **kwargs)
class Row(layout.Div):
def __init__(self, *fields, **kwargs):
css_class = 'form-inline form-group'
new_fields = [self.convert_field(f, len(fields)) for f in fields]
super(Row, self).__init__(css_class=css_class, *new_fields, **kwargs)
def convert_field(self, f, counts):
col_class = "col-sm-%d" % int(math.ceil(12 / counts))
if not (isinstance(f, Field) or issubclass(f.__class__, Field)):
f = layout.Field(f)
if f.wrapper_class:
f.wrapper_class += " %s" % col_class
else:
f.wrapper_class = col_class
return f
class Col(layout.Column):
def __init__(self, id, *fields, **kwargs):
css_class = ['column', 'form-column', id, 'col col-sm-%d' %
kwargs.get('span', 6)]
if kwargs.get('horizontal'):
css_class.append('form-horizontal')
super(Col, self).__init__(css_class=' '.join(css_class), *
fields, **kwargs)
class Main(layout.Column):
css_class = "column form-column main col col-sm-9 form-horizontal"
class Side(layout.Column):
css_class = "column form-column sidebar col col-sm-3"
class Container(layout.Div):
css_class = "form-container row clearfix"
# Override bootstrap3
class InputGroup(layout.Field):
template = "xadmin/layout/input_group.html"
def __init__(self, field, *args, **kwargs):
self.field = field
self.inputs = list(args)
if '@@' not in args:
self.inputs.append('@@')
self.input_size = None
css_class = kwargs.get('css_class', '')
if 'input-lg' in css_class:
self.input_size = 'input-lg'
if 'input-sm' in css_class:
self.input_size = 'input-sm'
super(InputGroup, self).__init__(field, **kwargs)
def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs):
classes = form.fields[self.field].widget.attrs.get('class', '')
extra_context = {
'inputs': self.inputs,
'input_size': self.input_size,
'classes': classes.replace('form-control', '')
}
if hasattr(self, 'wrapper_class'):
extra_context['wrapper_class'] = self.wrapper_class
return render_field(
self.field, form, form_style, context, template=self.template,
attrs=self.attrs, template_pack=template_pack, extra_context=extra_context, **kwargs)
class PrependedText(InputGroup):
def __init__(self, field, text, **kwargs):
super(PrependedText, self).__init__(field, text, '@@', **kwargs)
class AppendedText(InputGroup):
def __init__(self, field, text, **kwargs):
super(AppendedText, self).__init__(field, '@@', text, **kwargs)
class PrependedAppendedText(InputGroup):
def __init__(self, field, prepended_text=None, appended_text=None, *args, **kwargs):
super(PrependedAppendedText, self).__init__(
field, prepended_text, '@@', appended_text, **kwargs)
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+72
View File
@@ -0,0 +1,72 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Azd325 <tim.kleinschmidt@gmail.com>, 2013
# Azd325 <tim.kleinschmidt@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: Azd325 <tim.kleinschmidt@gmail.com>\n"
"Language-Team: German (Germany) (http://www.transifex.com/projects/p/xadmin/language/de_DE/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de_DE\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] "%(sel)s von %(cnt)s markiert"
msgstr[1] "%(sel)s von %(cnt)s markiert"
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr "Neues Element"
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr "Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag Sonntag"
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr "So Mo Di Mi Do Fr Sa So"
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr "So Mo Di Mi Do Fr Sa So"
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr "Januar Februar März April Mai Juni Juli August September Oktober November Dezember"
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr "Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez"
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr "Heute"
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr "%a %d %b %Y %T %Z"
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr "vorm nachm"
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr "vorm nachm"
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr "%T"
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+69
View File
@@ -0,0 +1,69 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] ""
msgstr[1] ""
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr ""
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+76
View File
@@ -0,0 +1,76 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# byroncorrales <byroncorrales@gmail.com>, 2013
# byroncorrales <byroncorrales@gmail.com>, 2013
# sacrac <crocha09.09@gmail.com>, 2013
# netoxico <me@netoxico.com>, 2013
# netoxico <me@netoxico.com>, 2013
# sacrac <crocha09.09@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: sacrac <crocha09.09@gmail.com>\n"
"Language-Team: Spanish (Mexico) (http://www.transifex.com/projects/p/xadmin/language/es_MX/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es_MX\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] "%(sel)s de %(cnt)s seleccionado."
msgstr[1] "%(sel)s de %(cnt)s seleccionado "
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr "Nuevo elemento"
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado Domingo"
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr "Dom Lun Mar Mié Jue Vie Sáb Dom"
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr "Do Lu Ma Mi Ju Vi Sá Do"
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr "Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre Noviembre Diciembre"
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr "Ene Feb Mar Abr May Jun Jul Ago Sep Oct Nov Dic"
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr "Hoy"
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr "%a %d %b %Y %T %Z"
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr "AM PM"
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr "am pm"
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr "%T"
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# unaizalakain <unai@gisa-elkartea.org>, 2013
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: unaizalakain <unai@gisa-elkartea.org>\n"
"Language-Team: Basque (http://www.transifex.com/projects/p/xadmin/language/eu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: eu\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] "%(cnt)stik %(sel)s aukeratua"
msgstr[1] "%(cnt)stik %(sel)s aukeratuak"
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr "Elementu Berria"
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr "Igandea Astelehena Asteartea Asteazkena Osteguna Ostirala Larunbata Igandea"
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr "Iga Atl Atr Atz Otg Otr Lar Iga"
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr "Ig At Ar Az Og Or La Ig"
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr "Urtarrila Otsaila Martxoa Apirila Maiatza Ekaina Uztaila Abuztua Iraila Urria Azaroa Abendua"
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr "Urt Ots Mar Api Mai Eka Uzt Abu Ira Urr Aza Abe"
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr "Gaur"
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr "%a %d %b %Y %T %Z"
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr "AM PM"
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr "am pm"
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr "%T"
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+69
View File
@@ -0,0 +1,69 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: sshwsfc <sshwsfc@gmail.com>\n"
"Language-Team: Indonesian (Indonesia) (http://www.transifex.com/projects/p/xadmin/language/id_ID/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: id_ID\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] ""
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr ""
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+69
View File
@@ -0,0 +1,69 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: sshwsfc <sshwsfc@gmail.com>\n"
"Language-Team: Japanese (http://www.transifex.com/projects/p/xadmin/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ja\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] ""
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr ""
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: sshwsfc <sshwsfc@gmail.com>\n"
"Language-Team: Lithuanian (http://www.transifex.com/projects/p/xadmin/language/lt/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: lt\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr ""
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+70
View File
@@ -0,0 +1,70 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: sshwsfc <sshwsfc@gmail.com>\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/xadmin/language/nl_NL/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: nl_NL\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] ""
msgstr[1] ""
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr ""
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+83
View File
@@ -0,0 +1,83 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: django-xadmin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-08-12 21:07+0200\n"
"PO-Revision-Date: 2014-08-12 21:23+0100\n"
"Last-Translator: Michał Szpadzik <mszpadzik@gmail.com>\n"
"Language-Team: Polish translators <mszpadzik@gmail.com>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 1.5.4\n"
#: static/xadmin/js/xadmin.plugin.actions.js:11
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] "%(sel)s z %(cnt)s wybranych"
msgstr[1] "%(sel)s z %(cnt)s wybranych"
msgstr[2] "%(sel)s z %(cnt)s wybranych"
#: static/xadmin/js/xadmin.plugin.quick-form.js:172
msgid "Close"
msgstr "Zamknij"
#: static/xadmin/js/xadmin.plugin.quick-form.js:173
msgid "Add"
msgstr "Dodaj"
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr "Nowy obiekt"
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr "niedziela poniedziałek wtorek środa czwartek piątek sobota niedziela"
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr "niedz. pon. wt. śr. czw. pt. sob. niedz."
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr "niedz. pn. wt. śr. czw. pt. sob. niedz."
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
"styczeń luty marzec kwiecień maj czerwiec lipiec sierpień wrzesień "
"październik "
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr "sty. lut. marz. kwie. maj czerw. lip. sier. wrze. paź. list. grudz."
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr "Dzisiaj"
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr "%a %d %b %Y %T %Z"
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr "AM PM"
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr "am pm"
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr "%T"
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# korndorfer <codigo.aberto@dorfer.com.br>, 2013
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: korndorfer <codigo.aberto@dorfer.com.br>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/xadmin/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt_BR\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] "%(sel)s de %(cnt)s selecionado"
msgstr[1] "%(sel)s de %(cnt)s selecionados"
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr "Novo Item"
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr "Domingo Segunda Terça Quarta Quinta Sexta Sábado Domingo"
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr "Dom Seg Ter Qua Qui Sex Sáb Dom"
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr "Do Sg Te Qa Qi Sx Sa Do"
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr "Janeiro Fevereiro Março Abril Maio Junho Julho Agosto Setembro Outubro Novembro Dezembro"
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr "Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez"
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr "Hoje"
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr "%a %d %b %Y %T %Z"
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr "AM PM"
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr "am pm"
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr "%T"
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: xadmin-core\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-04-30 23:11+0800\n"
"PO-Revision-Date: 2013-11-20 12:41+0000\n"
"Last-Translator: sshwsfc <sshwsfc@gmail.com>\n"
"Language-Team: Russian (Russia) (http://www.transifex.com/projects/p/xadmin/language/ru_RU/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru_RU\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: static/xadmin/js/xadmin.plugin.actions.js:20
msgid "%(sel)s of %(cnt)s selected"
msgid_plural "%(sel)s of %(cnt)s selected"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
#: static/xadmin/js/xadmin.plugin.revision.js:25
msgid "New Item"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:32
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:33
msgid "Sun Mon Tue Wed Thu Fri Sat Sun"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:34
msgid "Su Mo Tu We Th Fr Sa Su"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:35
msgid ""
"January February March April May June July August September October November"
" December"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:36
msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:37
msgid "Today"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:38
msgid "%a %d %b %Y %T %Z"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:39
msgid "AM PM"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:40
msgid "am pm"
msgstr ""
#: static/xadmin/js/xadmin.widget.datetime.js:43
msgid "%T"
msgstr ""

Some files were not shown because too many files have changed in this diff Show More