Setting permament Android PATHs on linux
Note published: 11/12/2020
Building a mobile app is not a simple task, not only because a developer must create oodles of efficient code, but also because there is a lot - and I mean A LOT - of settings to be dealt with. In order to launch and use all andorid-studio tools and libraries we must first consider organizing all related commands so that they won't throw errors whenever we need them. This short article is a result of my struggles with installing and re-installing Android-studio on different OS, like Linux and Mac OS. As you probably already know, you need an emulator in order to interact with your app in development. But one does not simply install and open an emulator (c). After downloading and insalling android-studio and sdk tools, you should correctly set all environment variables, that your emulator and other Android tools will use further on.
These variables are defining paths to Andoid's Sdk, emulator, tools and platform-tools. There are a number of ways to set them, but I choose to follow these steps:
1) check your $PATH.
$ echo $PATH
You might be surprised by the length of this basic variable and discover a lot of repeating lines. In case if this variable is messed up and seems to be build in haotic way, you may reset it to a default value with the following command:$ export PATH=$(getconf PATH)
export ANDROID_HOME=$HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
$ cd $HOME/Android/Sdk
$ source ~/.bash_profile
Now your enviroment variables are all set and you are good to go.
Serving multiple Django apps with Gunicorn and Nginx (CentOS 7)
Note published: 06/01/2020
It’s a real pleasure working with Django locally: thanks to SQLite and a simple built-in development webserver you are able to run all your applications with little or no effort at all. However deploy might become a headache. What to choose to serve your site, Apache or NginX, mod_wsgi or Gunicorn, or maybe something else or maybe all together? There are plenty of wonderful tutorials on how to deploy your Django app with our servers of choice — Gunicorn and NginX, but what if you have several apps and want to serve them on third-level domains, like for example if you have a professional portfolio consisting of many different websites on third-level domains with one common second-level domain? In this guide we will demonstrate how to achieve this goal on CentOS 7 (some steps and tools will differ on other Linux OS).
This guide uses a root user to simplify the demonstration, however for security reasons we recommend that you create another user with root privileges. You must have at least two ready-to-deploy Django apps and a fresh CentOS 7.
For each app we will use its own virtual environment, so you could use different Django versions and different settings in each venv. It doesn’t matter which database you use: in this guide we will use PostgreSQL for one app and SQLite for another.
Inside each app’s virtual env we will pip-install Gunicorn server and later create separate gunicorn.service and gunicorn.socket files for each project. We will then set up Nginx in front of Gunicorn instances and setup nginx.conf to listen to multiple sockets.
First lets make sure to have all our domains set up and ready to be connected to our django apps. For that we must login to our DNS control panel and create A-type DNS records for each site and direct them all to your CentOS 7 instance IP address.
With all our DNS settings ready, let’s setup your CentOS to serve django apps to these domains.
First of all, in order to use yum normally we need to install epel-release package:
$ yum install epel-release
After that we’ll be able to install, start and enable our general-purpose server of choice — nginx:
$ yum install nginx
$ systemctl start nginx
$ systemctl enable nginx
$ python -V
Python 2.7.5
$ yum install centos-release-scl
$ yum install rh-python36
$ scl enable rh-python36 bash
$ python -V
Python 3.6.3
$ getenforce
In case if response is “Enforcing”, Selinux will most likely refuse connection to your django app unless its configured to permit it, so either turn it off (setenforce Permissive) or configure it in the correct way (this tutorial will not cover this topic, but you can easily find a number of decent step-by-step guides on how to config selinux correctly). Let’s proceed. Create a new directory to store all your django projects in it: mkdir /var/www . Put all your django projects inside so that your www directory is structured like this:
/var/www/:
├── django_one
├── django_two
├── django_three
$ python3 -m venv django_one_venv
Later on you will have to specify this venv’s address in your gunicorn config file. Enable virtual environment:$ source django_one_venv/bin/activate
Install the corresponding Django version:$ (django_one_venv) pip install django==2.1
Install all additional packages or simply run the following command:$ (django_one_venv) python3 manage.py runserver django_one.your_domain.com:8000
At this point your app must be available on django_one.your_domain.com:8000, but now it is being served with django built-in server which is not acceptable for production, so let’s continue and set up gunicorn.$ (django_one_venv) pip install gunicorn
Moving on to the next step, let’s create django_one.socket and put it in /etc/systemd/system/:
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/django_one.sock
[Install]
WantedBy=sockets.target
[Unit]
Description=gunicorn daemon
Requires=django_one.socket
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/var/www/django_one
ExecStart=/django_one_venv/bin/gunicorn --workers 3 --bind unix:/run/django_one.sock \
django_one.wsgi:application
[Install]
WantedBy=multi-user.target
$ systemctl start django_one.socket
$ systemctl start django_one.service #equals to 'start gunicorn'
$ systemctl enable django_one.socket
$ systemctl enable django_one.service
server {
listen 80;
server_name django_one.your_domain.com;
location = /favicon.ico {
access_log off; log_not_found off;
}
location /static {
alias /var/www/django_one/static_root;
#or plain /var/www/django_one/static if you don’t use static_root in your django settings.py
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unix:/run/django_one.sock;
}
}
user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name django_one.your_domain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static {
alias /var/www/django_one/static_root;
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unix:/run/django_one.sock;
}
}
server {
listen 80;
server_name django_two.your_domain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static {
alias /var/www/django_two/static_root;
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unix:/run/django_two.sock;
}
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2 default_server;
# listen [::]:443 ssl http2 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
$ systemctl restart nginx
All the sockets and all the services specified for your django apps at this point must be up and running.Developing a mobile app with React-Native and Django REST framework, part 1: token authentication with Django REST auth, preparing a registration endpoint
Note published: 10/01/2020
Django REST framework is a modern, light and relatively quick solution to develop a full-capacity backend for any app, web or mobile. In terms of frontend, React-Native is one of the best ways to create mobile apps for both iOS and Android. Coupling these two amazing technologies seems like a perfect idea, and guess what - it is! In this tutorial we will be building a social network app which you can download from AppStore or Google Play.
First thing to do is create your directory which will contain both frontend and backend:
$ mkdir vetpetapp
$ cd vetpetapp
$ pip install django
$ django-admin startproject backend
$ cd vetpetapp/backend
$ python manage.py startapp users
INSTALLED_APPS = [
...
'users',
]
AUTH_USER_MODEL = 'users.CustomUser'
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
name = models.CharField(blank=True, max_length=255)
def __str__(self):
return self.email
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from . models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from . forms import CustomUserCreationForm, CustomUserChangeForm
from . models import CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['email', 'username', 'name']
admin.site.register(CustomUser, CustomUserAdmin)
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
$ pip install djangorestframework
$ pip install django-rest-auth
$ pip install django-allauth
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken', #since we are covering only token authentication here
'rest_auth',
'django.contrib.sites', #required by django-rest-auth package
'allauth',
'allauth.account',
'rest_auth.registration',
...
]
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# we need that since according to our configuration the system must send an email confirmation after a new user registers
SITE_ID = 1 # required by django.contrib.sites
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
# we've left only token authentication and in this tutorial we don't really need other types
],
}
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('vpa_api.urls')), # we instruct main conf to include urls from an app we must create - 'vpa_api'
path('users/', include('users.urls')), # and inculde urls from the app we've already created - 'users'
]
$ python manage.py startapp vpa_api
And don't forget to include it in your INSTALLED_APPS setting. After that we create a ne urls.py file inside the vpa_api dir and put this code inside:
from django.urls import include, path
urlpatterns = [
path('rest-auth/', include('rest_auth.urls')),
path('rest-auth/registration/', include('rest_auth.registration.urls')),
]
curl --header "Content-Type: application/json" \
--request POST \
# this is what our registration endpoint is expecting: username, email, password min. 8 char long with special symbols and password repeat
--data '{"username": "some_test_user", "email": "some_test_user@email.xz", "password1": "Some_long_and_valid_Password_0", "password2": "Some_long_and_valid_Password_0"}' \
http://127.0.0.1:8000/api/v1/rest-auth/registration/