---
# System prepended metadata

title: Django course

---

# 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 для быстрой доставки, тестирования и развертывания кода, вы можете значительно сократить задержку между написанием кода и его запуском в рабочей среде. 

![Docker system](https://docs.docker.com/engine/images/architecture.svg)

#### Установка
[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
![image](https://docs.docker.com/storage/images/types-of-mounts-volume.png)

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"

```
