# Django course
Project github:
## Summary
* [get & post](#Get-amp-Post)
* [blocking, pop-up message: before sending, you need save data](#Pop-Up-message-need-to-save)
* [paginations in classes (ListView)](#Pagination-in-ListView)
* [separate update and search form](#Separate-Form)
* [mixins, load data from excel](#Mixins)
* [GitHub, basic using and ?multiuser mode?](#Git)
* [databases](#Databases)
* [Docker](#Docker)
___
## Themes
### Get & Post
##### In function
```python=
def function_view(request):
if request.method != "POST"
raise HttpResponseNotAllowed("Method not allowed")
# Do anything
return HttpResponse("Some response")
```
*`request.method` maybe:*
* `GET` - getting data
* `POST` - add new data
* `PATCH` - spot update
* `PUT` - full update
* `DELETE` - remove obj
* `HEAD` - get metainfo (such as headers, status, cookies) from get method
*[Need use JS](https://jsfiddle.net/q9k54v1u/63/)*
##### In view class
```python=
class SomeView(View):
def get(self, request, *args, **kwargs):
data = request.GET
# https://some-site/path?first=1&second=2,
# QueryDict with first=1 and second=2
param_age = data.get("s_age")
if isinstance(param_age, int):
age = int(param_age)
else:
raise HttpResponseBadRequest("Param age must be integer")
# Do anything
return HttpResponse("Some response")
def post(self, request, *args, **kwargs):
data = request.POST
# Do anything
return HttpResponse("Some response")
def head(self, ...):
pass
# Your may add other methods, look above
```
#### Get POST data from get_context_data or get_queryset methods in ListView
```python=
class SomeListView(ListView):
def post(self, *args, **kwargs):
# Off HttpResponseNotAllowed errir
return super().get(*args, **kwargs)
def get_queryset(self):
post_data = self.request.POST
# Do anything
return SomeModel.objects.all()
```
### Pagination in ListView
###### some_app/views.py
```python=
class SomeListView(ListView):
model = Some # Some is Model
paginate_by = 2 # Count of items per page
# Default context_object_name eq. "some_list"
# as model name + _list
# Default template_name eq. some_list.html
# as model name + _list.html
```
###### templates/some_app/some_list.html
*Links on previos page next page and list pages*
```htmlmixed=
<!-- regular list -->
<ul class="some-list">
{% for some in some_list %}
<li>{{ some.some_field }}</li>
{% endfor %}
</ul>
<!-- end regular list -->
<!-- paginator -->
<ul class="paginator">
{% if page_obj.has_other_pages %}
{% if page_obj.has_previous %}
<li class="page-item">
<a
class="page-link"
href="?page={{ page_obj.previous_page_number }}"
>Пред.</a>
</li>
{% endif %}
{% for p in page_obj.paginator.page_range %}
{% if page_obj.number == p %}
<li
class="page-item active"
aria-current="page"
><a
class="page-link"
href="?page={{ p }}"
>{{ p }}<span class="sr-only"></span></a>
</li>
{% elif p > page_obj.number|add:-5 and p < page_obj.number|add:5 %}
<li class="page-item">
<a
class="page-link"
href="?page={{ p }}"
>{{ p }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a
class="page-link"
href="?page={{ page_obj.next_page_number }}"
>След.</a>
</li>
{% endif %}
{% else %}
Эта страница единственная
{% endif %}
</ul>
<!-- end paginator -->
```
### Git
> global information tracker, version control system designed to handle everything from small to very large projects with speed and efficiency.
* SignUp
* Create ssh cert & upload public to GitHub
* `ssh-keygen -t rsa -b 4096 -C "your@mail.com"`
* Paste this public key `cat .ssh/id_rsa.pub` to [GitHub ssh keys](https://github.com/settings/ssh/new)
* Create repo
* Prepare code to using git
* Linter such as `black`
* Create `requirements.txt`
* Create some description README.md ([MarkDown ref](https://htmlacademy.ru/blog/articles/markdown))
* Maybe `.env`
* Install git ([windows](https://github.com/git-for-windows/git/releases/download/v2.36.1.windows.1/Git-2.36.1-64-bit.exe), [linux](https://git-scm.com/download/linux))
* Git basic using
* *if need*, basic using terminal ( `cd`, `ls`, `rm`, `mv` )
* `git help` & `git help COMMAND( ex. remote )`
* Setup git: `git config --global KEY VALUE`
- `init.defaultBranch` - default branch, `master` or `main`
- `user.name` - user name
- `user.email` - user email
- `pull.ff only` - no rebase on pull
* `git init` ( `-b master_branch` )
* file .gitignore, autogenerator [gitignore.io](https://gitignore.io)
* `remote`
( `add` | `remove` | `get-url` | `set-url` | `rename` ) save local changes
* `git status`
* `git add` ( `.` | `-a` | `./README.md` )
* `git commit` ( `-m "message"` | `-am "message"` )
* `git rm` ( `-r .` | `./file` )
* `git rebase branch`
* `git branch` ( `-a` | `-D old_branch` | `-M renamed_branch` | `-C copied_branch` )
* `git log`
* `git reset HEAD~1`
* `git checkout` ( `-- .` | `-b new_branch` | `some_branch` )
* `git push remote branch` ( `--set-upstream` ) upload to remote repo code
* `git pull remote branch` ( `--set-upstream` ) get commits from remote
* `git clone git://github.com/user/repo.git dir`
### Databases
#### Intro, connection to another db
##### Example configs for MS SQL
*Be later*
##### Example configs for MySQL
```python=
DATABASES = {
"some_database": {
"ENGINE": "django.db.backends.mysql",
"NAME": "some_database",
"USER": "root",
"PASSWORD": "your_password",
"HOST": "127.0.0.1",
"PORT": "3306",
}
}
```
Install client: `pip install mysqlclient`
##### Example configs for PostgreSQL
```python=
DATABASES = {
"some_database": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": "some_database",
"USER": "root",
"PASSWORD": "your_password",
"HOST": "127.0.0.1",
"PORT": "3306",
}
}
'ENGINE': '',
```
Install client: `pip install psycopg2`
#### Some databases
Using for:
* replications
* sharing tables
#### Example replications
> Need using `replicas` for read and `primary` for write
###### app/settings.py
```python=
DATABASES = {
'default': {},
'primary': {
# some configs
},
'replica1': {
# some configs
},
'replica2': {
# some configs
},
...
}
DATABASE_ROUTERS = ['app.databases.ReplicationRouter']
```
###### app/databases.py
```python=
class ReplicationRouter:
def db_for_read(self, model, **hints):
return random.choice(['replica1', 'replica2'])
# Maybe add complex control based on response time or anything
def db_for_write(self, model, **hints):
# In replication mode, write occurs only in primary database
return 'primary'
def allow_relation(self, obj1, obj2, **hints):
# Relation with tables: foregn key and other
db_set = {'primary', 'replica1', 'replica2'}
if obj1._state.db in db_set and obj2._state.db in db_set:
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
# For makemigrations and search errors
return True
```
#### Sharing tables
###### app/settings.py
```python=
DATABASES = {
'default': {
# Some configs
},
'other_db': {
# Some configs
}
}
DATABASE_ROUTERS = ['app.databases.AuthRouter']
```
###### app/databases.py
```python=
class OtherRouter:
route_app_labels = {'other', 'contenttypes'}
def db_for_read(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return 'other_db'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return 'other_db'
return None
def allow_relation(self, obj1, obj2, **hints):
if (
obj1._meta.app_label in self.route_app_labels or
obj2._meta.app_label in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label in self.route_app_labels:
return db == 'other_db'
return None
```
### Docker
> Docker -- это открытая платформа для разработки, доставки и запуска приложений. Docker позволяет вам отделить ваши приложения от вашей инфраструктуры, чтобы вы могли быстро доставлять программное обеспечение. С помощью Docker вы можете управлять своей инфраструктурой так же, как вы управляете своими приложениями. Воспользовавшись методологиями Docker для быстрой доставки, тестирования и развертывания кода, вы можете значительно сократить задержку между написанием кода и его запуском в рабочей среде.

#### Установка
[Windows](https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe)
*Может потребоваться установка WSL2*
##### Command: run
> Run docker container
```shell=
docker run -it ubuntu /bin/bash
```
Where:
* `-i` -- interactive mode
* `-t` -- tty mode, attach to terminal
* `ubuntu` -- image name
* `/bin/bash` -- runned command
Other params:
* `--volume` or `-v` ( `name_volume_or_host_path:/path/in/container:other,params` )
* `--mount` params one line, splitted `,`
* `type=`:
* `volume` -- virtual
* `bind` -- some host folder or file
* `tmpfs` -- in memory
* `src=`, optional: `./local/path`
* `dst=` | `target=`: `/container/path`
* `volume-opt` -- other params
* `readonly`, optional
* `--secret source=some_secret,target=name_secret,mode=0400`
* `-p 9000:1000`, `9000` -- host port, `1000` -- container host
* `-e name:value` -- enviroment variable
##### Some commands
* `ps` - list runned containers
* `-a` - all containers
* `stats` -- resource usage
* `inspect some-container` -- get info about container or image
* `exec CONTAINER COMMAND` -- run command in container
* `-it` -- interactive mode
* `-d` -- detached
* `logs some-container` ( `-f` | `--tail 10` )
* `pause some-container`
* `restart some-container`
* `stop some-container`
* `cp` -- copy from host to container and opposite
* ex.: `container:/some/path ./host/path`
* ex.: `./host/path container:/some/path`
* `rm some-container`
* `rmi some-image`
* `top` as base linux `top`
* `kill some-container`
* `attach some-container`
##### volume

Create volume: `create new-volume`
List volume: `ls`
Info: `inspect some-volume`
Remove: `rm some-volume`
###### Example
```shell=
docker run -d \
--name devtest \
--mount source=myvol2,target=/app \
nginx:latest
```
##### secret
before: `docker swarm init`
* `create`
* ex.: `secret create file-secret some-file.txt`
* ex.: `secret create str-secret some-secret-string`
* `ls` -- get list of secrets
* `rm file-secret` -- remove secret
* `inspect file-secret` -- get info
```shell=
docker service create \
--name wordpress \
--secret source=some-secret,target=some-secret,mode=0400 \
--secret source=another-secret,target=/some-path/some-secret,mode=0400 \
nginx:latest
```
#### Create image
```dockerfile=
FROM python:alpine as builder
WORKDIR /app
ADD requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD python manage.py runserver
```
Build container: `docker build --tag dj-image .`
Some commands
* `docker images` -- list images
* `docker image`
* `prune` -- remove unused images
* `rm` -- remove
* `ls` -- list
## Docker-Compose
###### File: docker-compose.yml
```yaml=
services:
api:
build:
context: .
dockerfile: Dockerfile
depends_on:
- db
restart: always
volumes:
- "./host:./container"
ports:
- "9000:2111"
links:
- "db:some-db"
db:
image: mcr.microsoft.com/mssql/server
volumes:
environment:
ACCEPT_EULA: "Y"
SA_PASSWORD: "password"
```