{"id":25944849,"url":"https://github.com/raoul1996/robot_view_be","last_synced_at":"2026-04-09T12:49:26.424Z","repository":{"id":39846782,"uuid":"139173454","full_name":"Raoul1996/robot_view_be","owner":"Raoul1996","description":"robot attachment viewer backend","archived":false,"fork":false,"pushed_at":"2024-04-01T18:10:32.000Z","size":182,"stargazers_count":1,"open_issues_count":97,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-13T17:10:31.781Z","etag":null,"topics":["circleci","django","docker","docker-compose","jwt-authentication","postgres","python3","rest-framework-jwt","thrift-server","travis-ci"],"latest_commit_sha":null,"homepage":"http://robot.raoul1996.cn","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Raoul1996.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2018-06-29T16:43:41.000Z","updated_at":"2024-04-14T21:21:35.937Z","dependencies_parsed_at":"2023-09-27T05:41:48.048Z","dependency_job_id":"c53471a0-0c34-46c7-8e96-1b81812b9721","html_url":"https://github.com/Raoul1996/robot_view_be","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Raoul1996%2Frobot_view_be","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Raoul1996%2Frobot_view_be/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Raoul1996%2Frobot_view_be/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Raoul1996%2Frobot_view_be/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Raoul1996","download_url":"https://codeload.github.com/Raoul1996/robot_view_be/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241809548,"owners_count":20023791,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circleci","django","docker","docker-compose","jwt-authentication","postgres","python3","rest-framework-jwt","thrift-server","travis-ci"],"created_at":"2025-03-04T08:19:21.796Z","updated_at":"2025-12-30T22:55:10.139Z","avatar_url":"https://github.com/Raoul1996.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# robot\\_view\\_be\n\n\u003e robot attachment viewer backend\n\n[![Build Status](https://travis-ci.org/Raoul1996/robot_view_be.svg?branch=prod)](https://travis-ci.org/Raoul1996/robot_view_be)\n[![CircleCI](https://circleci.com/gh/Raoul1996/robot_view_be/tree/dev.svg?style=svg)](https://circleci.com/gh/Raoul1996/robot_view_be/tree/dev)\n\n## Run in development env\n\n### Install\n\n```bash\npip3 install -r ./requirement.txt\n```\n### Run\n\n```bash\npython3 manage.py runserver --settings=robot_view.dev_settings\n```\nor\n\n```bash\n./dev_robot.sh\n```\n## Run in Production env\n\nPlease install the docker-compose before you use it.\n\n```bash\ndocker-compose build \u0026\u0026 docker-compose up\n```\nthen visit the [localhost:8000](http://localhost:8000)\n\n## Resource\n1. [deployment via docker, nginx and uwsgi](https://github.com/yiyuhao/SanHui/tree/master/docker)\n2. [使用 CircleCI 实现持续集成和持续部署](https://ruiming.me/continuous-integration-and-deployment/)\n## Note\n\n### add a [README.md] to typing your note and problem\n\n### use docker in production env\nuse docker can make deploy more easy than before, and use the same system env can solve the cross-platform problems\n\n1. create the [Dockerfile](Dockerfile) file\n2. Install the `docker-compose` command tools and create the [docker-compose.yml](docker-compose.yml) file\n3. run `docker-compose build` to build the web image and database image, use `docker-compose run` to run these containers\n\n### use travis-ci to deploy the application automatic\n1. login travis-ci and add the current repos on github\n2. create the [`.travis.yml`](.travis.yml) in project\n3. add the ssh key by this command, in order to deploy the code to server\n\n```bash\ntravis encrypt-file ~/.ssh/id_rsa --add\n```\n### split the settings file for dev env and production env\n\nbecause I prefer using mysql database in the dev env, and use postgres in production env in docker container, so split the settings is very important.\nthere are many blog can search form google, just use the simplest method.\n\n1. create the [`dev_settings.py`](robot_view/dev_settings.py)\n2. import all item in [`settings.py`](robot_view/settings.py)\n3. overwrite the item what you want to change.\n4. run commands in [`manage.py`](manage.py) with `--settings=robot_view.dev_settings` or other settings file, default setting file is `settings.py` in `robot_view`\n\n### move app to apps path\nif app has very huge number, leave them in the project root path is not a smart choice, so create the `apps` path to store them\n\n1. modify the [`settings.py`](robot_view/settings.py), to configure the apps as resource path\n\n```python\nimport os\nimport sys\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\nsys.path.insert(0, os.path.join(BASE_DIR, 'apps'))\n```\n2. if use pycharm, also can mark the `apps` path as `Source Root`, trust me, It's a smart action.\n\n### change pip registry to douban\n\n```shell\npip3 install -r /code/robot/requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com\n```\nif use docker, modify the [Dockerfile](Dockerfile)\n\n```Dockerfile\n- RUN pip3 install -r /code/robot/requirements.txt\n+ RUN pip3 install -r /code/robot/requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com\n```\n### resolve the staticfiles 404:\n\nbecause Django will handle the request for the static file only when the `DEBUG` option in settings is `True`, if run in production env, developer must handle it by himself.\n\n1. declare the `STATIC_ROOT` in `settings.py`, or your custom setting files\n2. install `whitenoise` via pip and edit the [`wsgi.py`](robot_view/wsgi.py) in `robot_view`\n\n```shell\npip install whitenoise\n\n# export the dependencies in requirements.txt\npip freeze \u003e ./requirements.txt\n```\n```python\nfrom whitenoise.django import DjangoWhiteNoise\nfrom django.core.wsgi import get_wsgi_application\n\napplication = get_wsgi_application()\napplication = DjangoWhiteNoise(application)\n```\n3. then run this command:\n\n```shell\n# collect the static file from the package like rest-framework\n# to the STATIC_ROOT path where declare in settings file\npython manage.py collectstatic\n```\n4. then rebuild the docker image and run it\n\n```shell\n# -d option can make the process in daemon mode.\ndocker-compose build \u0026\u0026 docker-compose up -d\n```\n### and schema and docs\n\ndjango rest framework already support the docs and schema itself, just [include it and add a urlpatterns](apps/snippets/urls.py) is enough:\n\n```python\nfrom rest_framework.schemas import get_schema_view\nfrom django.urls import path, include\nfrom rest_framework.documentation import include_docs_urls\nfrom rest_framework.routers import DefaultRouter\n\nrouter = DefaultRouter()\nschema_view = get_schema_view(title=\"Server Monitoring API\")\n\nurlpatterns = [\n    path('', include(router.urls)),\n    path('schema/', schema_view),\n    path('docs/', include_docs_urls(title='doc', description='desc'))\n  ]\n```\n### Fix list is not callable\n\nAfter configure the router for user app, in development env, app can work very will, when build docker container, app throw a error: **list object is not callable**\n\nSolution is very easy: use the tuple, don't use list.\n\n```python\n# robot_view/setting.py\nREST_FRAMEWORK = {\n     # Use Django's standard `django.contrib.auth` permissions,\n     # or allow read-only access for unauthenticated users.\n     'DEFAULT_PERMISSION_CLASSES': (\n        'rest_framework.permissions.IsAuthenticated',\n    ),\n    'DEFAULT_AUTHENTICATION_CLASSES': (\n        # 'rest_framework_jwt.authentication.JSONWebTokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication',\n        'rest_framework.authentication.BasicAuthentication',\n    ),\n     'PAGE_SIZE': 10,\n    'DEFAULT_PAGINATION_CLASS': (\n        'rest_framework.pagination.PageNumberPagination'\n    )\n}\n```\n### Change authorization method to JWT\n\n- edit [setting.py](./robot_view/setting.py), and the `AUTHENTICATION_BACKENDS`\n\n    ```python\n    AUTHENTICATION_BACKENDS = (\n        'users.views.CustomBackend',\n        'django.contrib.auth.backends.ModelBackend'\n    )\n    ```\n\n- post the `username` and `password` to [http://127.0.0.1:8001/login/](http://127.0.0.1:8001/login/) to exchange the jwt\n- and `Authorization` request header and `Bearer` prefix for jwt string\n\n### Create thrift server in Django app\n\nfor rpc, I choose to use apache thrift framework\n\n- install `django-thrift`:\n\n    ```bash\n    pip install django-thrift\n    ```\n- configure `django-thrift` in [setting.py](robot_view/settings.py)\n    - add `'django_thrift'` in `INSTALLED_APPS`\n    - add `THRIFT` configure option in [setting.py](/robot_view/settings.py)\n    - add `FILE` option in `THRIFT` point to `*.thrift` file\n    - add `SERVICE` option named is the same to the `thrift` server name\n\n- write the thrift handler in django app `view`:\n\n    ```python\n    # import the create_handler\n    from django_thrift.handler import create_handler\n\n    # get a handler instantiation\n    handler = create_handler()\n\n    # defined the thrift method\n    @handler.map_function(\"saveRobotData\")\n    def save_robot_data_handler():\n        return {\"a\": \"bb\"}\n\n    # more thrift methods can be defined\n    ```\n\n- management thrift server on localhost 9090\n\n    ```bash\n    # start rpc server\n    python manage.py runrpcserver\n    ```\n### Create extra_app folder to store the library which have to modify the source code\n\nBecause I need change the thrift server listen host and port, but `django-thrift` library can't support change these in `setting.py`, so I have to modify the source code of this library.\n\n- create `extra_app` folder\n\n    ```bash\n    mkdir extra_app\n    ```\n- move the `django-thrift` library from `site-package` to `extra-app`:\n\n    ```bash\n    mv to_your_site_package_path/django-thrift extra_app\n    ```\n- add `extra-app` in `PYTHONPATH` via modify the [setting.py](robot_view/settings.py)\n\n    ```python\n    import sys, os\n    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n    sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))\n    ```\n- modify the `django-thrift` source code what you want to edit.\n\n### save password as django command 'createsuperuser'\n\nbefore I do these, only the user which create via django manage.py command `createsuperuser` can generate current JSON WEB Token. So I want to know why.\n\nthe user Profile data store in `users_userporfile` table, the password field which user is created by command is encrypted, so I need use the same methods to encrypt the password before save it in database.\n\nsearch in django source code, I find the [`make_password`](https://github.com/django/django/blob/stable%2F2.0.x/django/contrib/auth/hashers.py#L64) function, and when use create superuser, the manage.py don't provide the **salt**, so just use the like [base_user.py](https://github.com/django/django/blob/stable%2F2.0.x/django/contrib/auth/base_user.py#L97):\n\n```python\nfrom django.contrib.auth.hashers import make_password\ndef validate(self, attrs):\n    # because the limit from serializer, add 'raw_password' prop is forbidden.\n    # attrs[\"raw_password\"] = attrs[\"password\"]\n    attrs[\"password\"] = make_password(attrs[\"password\"])\n    return attrs\n```\n\n### use `Q` and rewrite retrieve method add prop on response\nthe minimum code implementation : \n\n```python\nfrom django.db.models import Q\nfrom django.contrib.auth import get_user_model\nfrom rest_framework import viewsets, status, response\nfrom rest_framework.mixins import  RetrieveModelMixin\nUser = get_user_model()\n\nclass ExampleViewSet(RetrieveModelMixin, viewsets.GenericViewSet):\n    def retrieve(self, request, *args, **kwargs):\n        queryset = self.get_object()\n        serializer = self.get_serializer(queryset)\n        re_dict = serializer.data\n        re_dict[\"username\"] = User.objects.get(Q(id=re_dict[\"user\"])).username\n        del re_dict[\"user\"]\n        headers = self.get_success_headers(serializer.data)\n        return response.Response(re_dict, status=status.HTTP_200_OK, headers=headers)\n```\n\n### use thrift application interface send data to sqlite database \n\nList Length | time\n------------|-------\n100         | 2s\n100,000     | 206s\n\n### nginx configuration\n\n```nginx\nserver {\n  listen 80;\n  server_name robot.raoul1996.cn;\n  root /usr/share/nginx/html/robot;\n  location / {\n  } \n  location ~* ^/api|static/ {\n    rewrite ^/api/(.*) /$1 break;\n    proxy_pass http://your_ip:your_port;\n  } \n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraoul1996%2Frobot_view_be","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraoul1996%2Frobot_view_be","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraoul1996%2Frobot_view_be/lists"}