gogs first init

Brightcells 9 anos atrás
commit
4defb80fdc

+ 29 - 0
.editorconfig

@@ -0,0 +1,29 @@
1
+# EditorConfig is awesome: http://EditorConfig.org
2
+
3
+# top-most EditorConfig file
4
+root = true
5
+
6
+# Unix-style newlines with a newline ending every file
7
+[*]
8
+end_of_line = lf
9
+insert_final_newline = false
10
+
11
+# 4 space indentation
12
+[*.py]
13
+indent_style = space
14
+indent_size = 4
15
+
16
+# Tab indentation (no size specified)
17
+[*.js]
18
+indent_style = space
19
+indent_size = 4
20
+
21
+# Tab indentation (no size specified)
22
+[*.html]
23
+indent_style = space
24
+indent_size = 4
25
+
26
+# Matches the exact files either package.json or .travis.yml
27
+[{package.json,.travis.yml}]
28
+indent_style = space
29
+indent_size = 2

+ 63 - 0
.gitignore

@@ -0,0 +1,63 @@
1
+# Byte-compiled / optimized / DLL files
2
+__pycache__/
3
+*.py[cod]
4
+*.swp
5
+# C extensions
6
+*.so
7
+
8
+# Distribution / packaging
9
+bin/
10
+build/
11
+develop-eggs/
12
+dist/
13
+eggs/
14
+lib/
15
+lib64/
16
+parts/
17
+sdist/
18
+venv/
19
+var/
20
+static/upload/
21
+*.egg-info/
22
+.installed.cfg
23
+*.egg
24
+*.sublime*
25
+
26
+# Installer logs
27
+pip-log.txt
28
+pip-delete-this-directory.txt
29
+
30
+# Unit test / coverage reports
31
+.tox/
32
+.coverage
33
+.cache
34
+nosetests.xml
35
+coverage.xml
36
+
37
+# Translations
38
+# *.mo
39
+
40
+# Mr Developer
41
+.mr.developer.cfg
42
+.project
43
+.pydevproject
44
+.settings
45
+# Rope
46
+.ropeproject
47
+
48
+# Django stuff:
49
+*.log
50
+*.pot
51
+
52
+# Sphinx documentation
53
+docs/_build/
54
+
55
+
56
+# Ignore For zhTimer
57
+.DS_Store
58
+db.sqlite3
59
+local_settings.py
60
+
61
+.idea/
62
+media/
63
+collect_static/

+ 0 - 0
account/__init__.py


+ 14 - 0
account/admin.py

@@ -0,0 +1,14 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from account.models import LensmanInfo
6
+
7
+
8
+class LensmanInfoAdmin(admin.ModelAdmin):
9
+    list_display = ('lensman_id', 'name', 'sex', 'phone', 'location', 'proportion', 'status', 'created_at', 'updated_at')
10
+    search_fields = ('name', 'phone', 'location')
11
+    list_filter = ('sex', 'status')
12
+
13
+
14
+admin.site.register(LensmanInfo, LensmanInfoAdmin)

+ 33 - 0
account/migrations/0001_initial.py

@@ -0,0 +1,33 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+import shortuuidfield.fields
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='LensmanInfo',
16
+            fields=[
17
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', verbose_name='status')),
19
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
20
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
21
+                ('lensman_id', shortuuidfield.fields.ShortUUIDField(help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', max_length=22, editable=False, db_index=True, blank=True)),
22
+                ('name', models.CharField(help_text='\u6444\u5f71\u5e08\u59d3\u540d', max_length=255, null=True, verbose_name='name', blank=True)),
23
+                ('sex', models.IntegerField(default=0, help_text='\u6444\u5f71\u5e08\u6027\u522b', verbose_name='sex', choices=[(0, '\u7537'), (1, '\u5973')])),
24
+                ('phone', models.CharField(null=True, max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u7535\u8bdd', unique=True, verbose_name='phone', db_index=True)),
25
+                ('location', models.CharField(help_text='\u6444\u5f71\u5e08\u5730\u5740', max_length=255, null=True, verbose_name='location', blank=True)),
26
+                ('proportion', models.FloatField(default=1.0, help_text='\u6444\u5f71\u5e08\u5206\u6210\u6bd4\u4f8b\uff080.0 \uff5e 1.0\uff09', verbose_name='proportion')),
27
+            ],
28
+            options={
29
+                'verbose_name': 'lensmaninfo',
30
+                'verbose_name_plural': 'lensmaninfo',
31
+            },
32
+        ),
33
+    ]

+ 0 - 0
account/migrations/__init__.py


+ 33 - 0
account/models.py

@@ -0,0 +1,33 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+
6
+from pai2.basemodels import CreateUpdateMixin
7
+
8
+from shortuuidfield import ShortUUIDField
9
+
10
+
11
+class LensmanInfo(CreateUpdateMixin):
12
+    MALE = 0
13
+    FEMALE = 1
14
+
15
+    SEX_TYPE = (
16
+        (MALE, u'男'),
17
+        (FEMALE, u'女'),
18
+    )
19
+
20
+    lensman_id = ShortUUIDField(_(u'lensman_id'), max_length=255, help_text=u'摄影师唯一标识', db_index=True)
21
+    name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'摄影师姓名')
22
+    sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE, default=MALE, help_text=u'摄影师性别')
23
+    phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'摄影师电话', db_index=True, unique=True)
24
+    location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'摄影师地址')
25
+
26
+    proportion = models.FloatField(_(u'proportion'), default=1.0, help_text=u'摄影师分成比例(0.0 ~ 1.0)')
27
+
28
+    class Meta:
29
+        verbose_name = _(u'lensmaninfo')
30
+        verbose_name_plural = _(u'lensmaninfo')
31
+
32
+    def __unicode__(self):
33
+        return unicode(self.pk)

+ 24 - 0
account/serializers.py

@@ -0,0 +1,24 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib.auth.models import User, Group
4
+from rest_framework import serializers
5
+
6
+from account.models import LensmanInfo
7
+
8
+
9
+class UserSerializer(serializers.HyperlinkedModelSerializer):
10
+    class Meta:
11
+        model = User
12
+        fields = ('url', 'username', 'email', 'groups')
13
+
14
+
15
+class GroupSerializer(serializers.HyperlinkedModelSerializer):
16
+    class Meta:
17
+        model = Group
18
+        fields = ('url', 'name')
19
+
20
+
21
+class LensmanInfoSerializer(serializers.HyperlinkedModelSerializer):
22
+    class Meta:
23
+        model = LensmanInfo
24
+        fields = ('lensman_id', 'name', 'sex', 'phone', 'location', 'proportion', 'created_at')

+ 3 - 0
account/tests.py

@@ -0,0 +1,3 @@
1
+from django.test import TestCase
2
+
3
+# Create your tests here.

+ 28 - 0
account/views.py

@@ -0,0 +1,28 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib.auth.models import User, Group
4
+from rest_framework import viewsets
5
+
6
+from account.models import LensmanInfo
7
+from account.serializers import UserSerializer, GroupSerializer, LensmanInfoSerializer
8
+
9
+
10
+class UserViewSet(viewsets.ModelViewSet):
11
+    """
12
+    API endpoint that allows users to be viewed or edited.
13
+    """
14
+    queryset = User.objects.all().order_by('-date_joined')
15
+    serializer_class = UserSerializer
16
+
17
+
18
+class GroupViewSet(viewsets.ModelViewSet):
19
+    """
20
+    API endpoint that allows groups to be viewed or edited.
21
+    """
22
+    queryset = Group.objects.all()
23
+    serializer_class = GroupSerializer
24
+
25
+
26
+class LensmanInfoViewSet(viewsets.ModelViewSet):
27
+    queryset = LensmanInfo.objects.all().order_by('-created_at')
28
+    serializer_class = LensmanInfoSerializer

+ 0 - 0
api/__init__.py


+ 3 - 0
api/admin.py

@@ -0,0 +1,3 @@
1
+from django.contrib import admin
2
+
3
+# Register your models here.

+ 0 - 0
api/migrations/__init__.py


+ 3 - 0
api/models.py

@@ -0,0 +1,3 @@
1
+from django.db import models
2
+
3
+# Create your models here.

+ 3 - 0
api/tests.py

@@ -0,0 +1,3 @@
1
+from django.test import TestCase
2
+
3
+# Create your tests here.

+ 10 - 0
api/urls.py

@@ -0,0 +1,10 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf.urls import url
4
+
5
+from photo import views as photo_views
6
+
7
+
8
+urlpatterns = [
9
+    url(r'^photos/upload$', photo_views.upload_photo, name='upload_photo'),
10
+]

+ 3 - 0
api/views.py

@@ -0,0 +1,3 @@
1
+from django.shortcuts import render
2
+
3
+# Create your views here.

+ 10 - 0
manage.py

@@ -0,0 +1,10 @@
1
+#!/usr/bin/env python
2
+import os
3
+import sys
4
+
5
+if __name__ == "__main__":
6
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pai2.settings")
7
+
8
+    from django.core.management import execute_from_command_line
9
+
10
+    execute_from_command_line(sys.argv)

+ 0 - 0
pai2/__init__.py


+ 14 - 0
pai2/basemodels.py

@@ -0,0 +1,14 @@
1
+#!/usr/bin/env python
2
+# -*- coding: utf-8 -*-
3
+
4
+from django.db import models
5
+from django.utils.translation import ugettext_lazy as _
6
+
7
+
8
+class CreateUpdateMixin(models.Model):
9
+    status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'))
10
+    created_at = models.DateTimeField(_(u'created_at'), auto_now_add=True, editable=True, help_text=_(u'创建时间'))
11
+    updated_at = models.DateTimeField(_(u'updated_at'), auto_now=True, editable=True, help_text=_(u'更新时间'))
12
+
13
+    class Meta:
14
+        abstract = True

+ 147 - 0
pai2/settings.py

@@ -0,0 +1,147 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""
4
+Django settings for pai2 project.
5
+
6
+Generated by 'django-admin startproject' using Django 1.8.4.
7
+
8
+For more information on this file, see
9
+https://docs.djangoproject.com/en/1.8/topics/settings/
10
+
11
+For the full list of settings and their values, see
12
+https://docs.djangoproject.com/en/1.8/ref/settings/
13
+"""
14
+
15
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16
+import os
17
+
18
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
19
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
20
+
21
+
22
+# Quick-start development settings - unsuitable for production
23
+# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
24
+
25
+# SECURITY WARNING: keep the secret key used in production secret!
26
+SECRET_KEY = 'aam6@6bh17d87bn-ax1@mcdrtbfm02y)_twd&!ewrr2^4581!c'
27
+
28
+# SECURITY WARNING: don't run with debug turned on in production!
29
+DEBUG = True
30
+
31
+ALLOWED_HOSTS = []
32
+
33
+
34
+# Application definition
35
+
36
+INSTALLED_APPS = (
37
+    'django.contrib.admin',
38
+    'django.contrib.auth',
39
+    'django.contrib.contenttypes',
40
+    'django.contrib.sessions',
41
+    'django.contrib.messages',
42
+    'django.contrib.staticfiles',
43
+    'rest_framework',
44
+    'api',
45
+    'account',
46
+    'photo',
47
+)
48
+
49
+MIDDLEWARE_CLASSES = (
50
+    'django.contrib.sessions.middleware.SessionMiddleware',
51
+    'django.middleware.common.CommonMiddleware',
52
+    # 'django.middleware.csrf.CsrfViewMiddleware',
53
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
54
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
55
+    'django.contrib.messages.middleware.MessageMiddleware',
56
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
57
+    'django.middleware.security.SecurityMiddleware',
58
+)
59
+
60
+ROOT_URLCONF = 'pai2.urls'
61
+
62
+TEMPLATES = [
63
+    {
64
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
65
+        'DIRS': [],
66
+        'APP_DIRS': True,
67
+        'OPTIONS': {
68
+            'context_processors': [
69
+                'django.template.context_processors.debug',
70
+                'django.template.context_processors.request',
71
+                'django.contrib.auth.context_processors.auth',
72
+                'django.contrib.messages.context_processors.messages',
73
+            ],
74
+        },
75
+    },
76
+]
77
+
78
+WSGI_APPLICATION = 'pai2.wsgi.application'
79
+
80
+
81
+# Database
82
+# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
83
+
84
+DATABASES = {
85
+    'default': {
86
+        'ENGINE': 'django.db.backends.mysql',
87
+        'NAME': 'pai2',
88
+        'USER': 'root',
89
+        'PASSWORD': '',
90
+    }
91
+}
92
+
93
+
94
+# Internationalization
95
+# https://docs.djangoproject.com/en/1.8/topics/i18n/
96
+
97
+LANGUAGE_CODE = 'zh_CN'
98
+
99
+TIME_ZONE = 'Asia/Shanghai'
100
+
101
+USE_I18N = True
102
+
103
+USE_L10N = True
104
+
105
+USE_TZ = True
106
+
107
+
108
+# Static files (CSS, JavaScript, Images)
109
+# https://docs.djangoproject.com/en/1.8/howto/static-files/
110
+
111
+STATICFILES_DIRS = (
112
+    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
113
+)
114
+
115
+STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
116
+
117
+STATIC_URL = '/static/'
118
+
119
+STATICFILES_FINDERS = (
120
+    'django.contrib.staticfiles.finders.FileSystemFinder',
121
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
122
+    # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
123
+)
124
+
125
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
126
+
127
+MEDIA_URL = '/media/'
128
+
129
+# REST_FRAMEWORK 设置
130
+# See http://www.django-rest-framework.org/#example
131
+REST_FRAMEWORK = {
132
+    # Use Django's standard `django.contrib.auth` permissions,
133
+    # or allow read-only access for unauthenticated users.
134
+    # 'DEFAULT_PERMISSION_CLASSES': [
135
+    #     'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
136
+    # ]
137
+    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',),
138
+    'PAGE_SIZE': 1
139
+}
140
+
141
+# 域名设置
142
+DOMAIN = 'http://xfoto.com.cn'
143
+
144
+try:
145
+    from local_settings import *
146
+except ImportError:
147
+    pass

+ 48 - 0
pai2/urls.py

@@ -0,0 +1,48 @@
1
+"""pai2 URL Configuration
2
+
3
+The `urlpatterns` list routes URLs to views. For more information please see:
4
+    https://docs.djangoproject.com/en/1.8/topics/http/urls/
5
+Examples:
6
+Function views
7
+    1. Add an import:  from my_app import views
8
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
9
+Class-based views
10
+    1. Add an import:  from other_app.views import Home
11
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
12
+Including another URLconf
13
+    1. Add an import:  from blog import urls as blog_urls
14
+    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
15
+"""
16
+from django.conf import settings
17
+from django.conf.urls import include, url
18
+from django.conf.urls.static import static
19
+from django.contrib import admin
20
+
21
+from rest_framework import routers
22
+from account import views as account_views
23
+from photo import views as photo_views
24
+
25
+router = routers.DefaultRouter()
26
+# router.register(r'users', account_views.UserViewSet)
27
+# router.register(r'groups', account_views.GroupViewSet)
28
+router.register(r'lensmans', account_views.LensmanInfoViewSet)
29
+router.register(r'photos', photo_views.PhotoInfoViewSet)
30
+
31
+urlpatterns = [
32
+    url(r'^pai2admin/', include(admin.site.urls)),
33
+]
34
+
35
+urlpatterns += [
36
+    url(r'^api/', include('api.urls', namespace='api')),
37
+    # url(r'^photo/', include('photo.urls', namespace='photo'))
38
+]
39
+
40
+# Wire up our API using automatic URL routing.
41
+# Additionally, we include login URLs for the browsable API.
42
+urlpatterns += [
43
+    url(r'^api/', include(router.urls)),
44
+    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
45
+]
46
+
47
+urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
48
+urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 22 - 0
pai2/uwsgi.bak/pai2.ini

@@ -0,0 +1,22 @@
1
+# morefun_uwsgi.ini file
2
+[uwsgi]
3
+
4
+# Django-related settings
5
+# the base directory (full path)
6
+chdir           = /home/paiai/work/pai2
7
+# Django's wsgi file
8
+module          = pai2.wsgi
9
+# the virtualenv (full path)
10
+# home            = /path/to/virtualenv
11
+
12
+# process-related settings
13
+# master
14
+master          = true
15
+# maximum number of worker processes
16
+processes       = 10
17
+# the socket (use the full path to be safe
18
+socket          = /home/paiai/work/pai2/pai2/uwsgi/pai2.sock
19
+# ... with appropriate permissions - may be needed
20
+chmod-socket    = 777
21
+# clear environment on exit
22
+vacuum          = true

+ 35 - 0
pai2/uwsgi.bak/pai2_nginx.conf

@@ -0,0 +1,35 @@
1
+# pai2_nginx.conf
2
+
3
+# the upstream component nginx needs to connect to
4
+upstream pai2 {
5
+    # server unix:///home/paiai/work/pai2/pai2/uwsgi/pai2.sock; # for a file socket
6
+    server 127.0.0.1:8888; # for a web port socket (we'll use this first)
7
+}
8
+
9
+# configuration of the server
10
+server {
11
+    # the port your site will be served on
12
+    listen      80;
13
+    # the domain name it will serve for
14
+    server_name .xfoto.com.cn; # substitute your machine's IP address or FQDN
15
+    charset     utf-8;
16
+
17
+    # max upload size
18
+    client_max_body_size 75M;   # adjust to taste
19
+
20
+    # Django media
21
+    location /media  {
22
+        alias /home/paiai/work/pai2/media;  # your Django project's media files - amend as required
23
+    }
24
+
25
+    location /static {
26
+        alias /home/paiai/work/pai2/collect_static; # your Django project's static files - amend as required
27
+    }
28
+
29
+    # Finally, send all non-media requests to the Django server.
30
+    location / {
31
+        # uwsgi_pass  pai2;
32
+        proxy_pass  http://pai2;
33
+        include     /home/paiai/work/pai2/pai2/uwsgi/uwsgi_params; # the uwsgi_params file you installed
34
+    }
35
+}

+ 2 - 0
pai2/uwsgi.bak/shutdown.sh

@@ -0,0 +1,2 @@
1
+killall -9 uwsgi
2
+echo "2敏加油~~~!!!↖(^ω^)↗"

+ 2 - 0
pai2/uwsgi.bak/startup.sh

@@ -0,0 +1,2 @@
1
+nohup uwsgi --ini pai2.ini &>pai2.log &
2
+echo "Start Success !!!"

+ 15 - 0
pai2/uwsgi.bak/uwsgi_params

@@ -0,0 +1,15 @@
1
+uwsgi_param	QUERY_STRING		$query_string;
2
+uwsgi_param	REQUEST_METHOD		$request_method;
3
+uwsgi_param	CONTENT_TYPE		$content_type;
4
+uwsgi_param	CONTENT_LENGTH		$content_length;
5
+
6
+uwsgi_param	REQUEST_URI		$request_uri;
7
+uwsgi_param	PATH_INFO		$document_uri;
8
+uwsgi_param	DOCUMENT_ROOT		$document_root;
9
+uwsgi_param	SERVER_PROTOCOL		$server_protocol;
10
+uwsgi_param	UWSGI_SCHEME		$scheme;
11
+
12
+uwsgi_param	REMOTE_ADDR		$remote_addr;
13
+uwsgi_param	REMOTE_PORT		$remote_port;
14
+uwsgi_param	SERVER_PORT		$server_port;
15
+uwsgi_param	SERVER_NAME		$server_name;

+ 3 - 0
pai2/views.py

@@ -0,0 +1,3 @@
1
+from django.shortcuts import render
2
+
3
+# Create your views here.

+ 16 - 0
pai2/wsgi.py

@@ -0,0 +1,16 @@
1
+"""
2
+WSGI config for pai2 project.
3
+
4
+It exposes the WSGI callable as a module-level variable named ``application``.
5
+
6
+For more information on this file, see
7
+https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
8
+"""
9
+
10
+import os
11
+
12
+from django.core.wsgi import get_wsgi_application
13
+
14
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pai2.settings")
15
+
16
+application = get_wsgi_application()

+ 9 - 0
pep8.sh

@@ -0,0 +1,9 @@
1
+#!/bin/bash
2
+
3
+# Ignoring autogenerated files
4
+#  -- Migration directories
5
+# Ignoring error codes
6
+#  -- E128 continuation line under-indented for visual indent
7
+#  -- E501 line too long
8
+
9
+pep8 --exclude=migrations --ignore=E128,E501 .

+ 0 - 0
photo/__init__.py


+ 13 - 0
photo/admin.py

@@ -0,0 +1,13 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from photo.models import PhotosInfo
6
+
7
+
8
+class PhotosInfoAdmin(admin.ModelAdmin):
9
+    list_display = ('lensman_id', 'session_id', 'photo_id', 'photo_path', 'status', 'created_at', 'updated_at')
10
+    list_filter = ('lensman_id', 'status')
11
+
12
+
13
+admin.site.register(PhotosInfo, PhotosInfoAdmin)

+ 34 - 0
photo/migrations/0001_initial.py

@@ -0,0 +1,34 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+    ]
11
+
12
+    operations = [
13
+        migrations.CreateModel(
14
+            name='PhotosInfo',
15
+            fields=[
16
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
17
+                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', verbose_name='status')),
18
+                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
19
+                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
20
+                ('lesman_id', models.CharField(max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='lesman_id', db_index=True)),
21
+                ('session_id', models.CharField(max_length=255, blank=True, help_text='\u7167\u7247\u7ec4\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='session_id', db_index=True)),
22
+                ('photo_id', models.CharField(null=True, max_length=255, blank=True, help_text='\u7167\u7247\u552f\u4e00\u6807\u8bc6', unique=True, verbose_name='photo_id', db_index=True)),
23
+                ('photo_path', models.CharField(help_text='\u7167\u7247\u5b58\u653e\u8def\u5f84', max_length=255, null=True, verbose_name='photo_path', blank=True)),
24
+            ],
25
+            options={
26
+                'verbose_name': 'photosinfo',
27
+                'verbose_name_plural': 'photosinfo',
28
+            },
29
+        ),
30
+        migrations.AlterIndexTogether(
31
+            name='photosinfo',
32
+            index_together=set([('lesman_id', 'session_id')]),
33
+        ),
34
+    ]

+ 27 - 0
photo/migrations/0002_auto_20151113_1419.py

@@ -0,0 +1,27 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.db import models, migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('photo', '0001_initial'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='photosinfo',
16
+            name='lensman_id',
17
+            field=models.CharField(max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='lensman_id', db_index=True),
18
+        ),
19
+        migrations.AlterIndexTogether(
20
+            name='photosinfo',
21
+            index_together=set([('lensman_id', 'session_id')]),
22
+        ),
23
+        migrations.RemoveField(
24
+            model_name='photosinfo',
25
+            name='lesman_id',
26
+        ),
27
+    ]

+ 0 - 0
photo/migrations/__init__.py


+ 39 - 0
photo/models.py

@@ -0,0 +1,39 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf import settings
4
+from django.db import models
5
+from django.utils.translation import ugettext_lazy as _
6
+
7
+from pai2.basemodels import CreateUpdateMixin
8
+
9
+
10
+class PhotosInfo(CreateUpdateMixin):
11
+    lensman_id = models.CharField(_(u'lensman_id'), max_length=255, blank=True, null=True, help_text=u'摄影师唯一标识', db_index=True)
12
+    session_id = models.CharField(_(u'session_id'), max_length=255, blank=True, null=True, help_text=u'照片组唯一标识', db_index=True)
13
+    photo_id = models.CharField(_(u'photo_id'), max_length=255, blank=True, null=True, help_text=u'照片唯一标识', db_index=True, unique=True)
14
+    photo_path = models.CharField(_(u'photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径')
15
+
16
+    class Meta:
17
+        verbose_name = _('photosinfo')
18
+        verbose_name_plural = _('photosinfo')
19
+        index_together = [
20
+            ['lensman_id', 'session_id'],
21
+        ]
22
+
23
+    def __unicode__(self):
24
+        return u'{0.pk}'.format(self)
25
+
26
+    @property
27
+    def photo_url(self):
28
+        return u'{0}/media/{1}'.format(settings.DOMAIN, self.photo_path) if self.photo_path else ''
29
+
30
+    def _data(self):
31
+        return {
32
+            'pk': self.pk,
33
+            'lensman_id': self.lensman_id,
34
+            'session_id': self.session_id,
35
+            'photo_id': self.photo_id,
36
+            'photo_url': self.photo_url,
37
+        }
38
+
39
+    data = property(_data)

+ 10 - 0
photo/serializers.py

@@ -0,0 +1,10 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from photo.models import PhotosInfo
4
+from rest_framework import serializers
5
+
6
+
7
+class PhotosInfoSerializer(serializers.HyperlinkedModelSerializer):
8
+    class Meta:
9
+        model = PhotosInfo
10
+        fields = ('lensman_id', 'session_id', 'photo_id', 'photo_path', 'created_at')

+ 3 - 0
photo/tests.py

@@ -0,0 +1,3 @@
1
+from django.test import TestCase
2
+
3
+# Create your tests here.

+ 0 - 0
photo/urls.py


+ 71 - 0
photo/views.py

@@ -0,0 +1,71 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.core.files.storage import default_storage
4
+from django.http import JsonResponse
5
+
6
+from rest_framework import viewsets
7
+
8
+from account.models import LensmanInfo
9
+from photo.models import PhotosInfo
10
+from photo.serializers import PhotosInfoSerializer
11
+
12
+import os
13
+
14
+
15
+# [How to do a PUT request with curl?](http://stackoverflow.com/questions/13782198/how-to-do-a-put-request-with-curl)
16
+# Unfortunately, the -T is no substitute for -X PUT if you want to specify parameters with -d or -F.
17
+# -T sends the content of a file via PUT. To achieve the GET after a redirect, add the parameter --location
18
+#
19
+# -F, --form <name=content>
20
+#               (HTTP)  This  lets  curl emulate a filled-in form in which a user has pressed the submit button. This causes curl to POST data
21
+#               using the Content-Type multipart/form-data according to RFC 2388. This enables uploading of binary files  etc.  To  force  the
22
+#               'content'  part  to  be a file, prefix the file name with an @ sign. To just get the content part from a file, prefix the file
23
+#               name with the symbol <. The difference between @ and < is then that @ makes a file get attached in the post as a file  upload,
24
+#               while the < makes a text field and just get the contents for that text field from a file.
25
+#
26
+# curl -X POST -F lensman_id=123 -F session_id=456 -F photo_id=789 -F photo=@7056288a9ddf2db294cf50a943920989.jpg;filename=789 http://xfoto.com.cn/api/photos/upload
27
+def upload_photo(request):
28
+    lensman_id = request.POST.get('lensman_id', '')
29
+    session_id = request.POST.get('session_id', '')
30
+    photo_id = request.POST.get('photo_id', '')
31
+
32
+    photo = request.FILES.get('photo', '')
33
+
34
+    if not (lensman_id and session_id and photo_id and photo):
35
+        return JsonResponse({
36
+            'status': 400,
37
+            'message': u'参数错误',
38
+        })
39
+
40
+    try:
41
+        LensmanInfo.objects.get(lensman_id=lensman_id)
42
+    except LensmanInfo.DoesNotExist:
43
+        return JsonResponse({
44
+            'status': 400,
45
+            'message': u'参数错误',
46
+        })
47
+
48
+    _, extension = os.path.splitext(photo.name)
49
+    photo_path = 'photo/{0}/{1}/{2}{3}'.format(lensman_id, session_id, photo_id, extension)
50
+
51
+    if default_storage.exists(photo_path):
52
+        default_storage.delete(photo_path)
53
+    default_storage.save(photo_path, photo)
54
+
55
+    photo, created = PhotosInfo.objects.get_or_create(
56
+        lensman_id=lensman_id,
57
+        session_id=session_id,
58
+        photo_id=photo_id,
59
+        photo_path=photo_path
60
+    )
61
+
62
+    return JsonResponse({
63
+        'status': 200,
64
+        'message': u'照片上传成功',
65
+        'data': photo.data,
66
+    })
67
+
68
+
69
+class PhotoInfoViewSet(viewsets.ModelViewSet):
70
+    queryset = PhotosInfo.objects.all().order_by('-created_at')
71
+    serializer_class = PhotosInfoSerializer

+ 12 - 0
requirements.txt

@@ -0,0 +1,12 @@
1
+CodeConvert==2.0.3
2
+Django==1.8.4
3
+MySQL-python==1.2.5
4
+TimeConvert==1.0.7
5
+django-shortuuidfield==0.1.3
6
+djangorestframework==3.3.1
7
+ipdb==0.8.1
8
+ipython==4.0.0
9
+pep8==1.6.2
10
+pillow==2.9.0
11
+pytz==2015.7
12
+uWSGI==2.0.11.1