Создание модели ORM, вывод из базы данных в шаблоны Django

👁 140 просмотров
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Загрузка...

Теория

В данном посте будем работать с базой данных в Django и в частности, рассмотрим такой механизм работы с БД, как ORM.

ORM(Object Relation Mapping) — Объектно ориентированное наложение базы данных. Т.е., это означает, что мы создаем в базе данных таблицы и связи на основе классов и их свойств, которых мы определяем в файле models.py в приложении Django.

Примечание. Процесс экспорта из models.py в базу данных в Django называется миграцией БД.

Плюс ORM  в том, что вам не обязательно вникать в суть того, какие именно БД вы будете использовать. Достаточно установить в систему сервер БД и указать в файлах настройки, что мы будем использовать эту БД, а все ньюансы CRUD с базой данных возьмет на себя общий интерфейс ORM.

В дальнейшем, чтобы, делать выборку или чтобы хранить, редактировать или удалить данные мы будем использовать только функции ORM.

Каждый объект класса в models.py — это отдельная таблица в БД, который, после миграции используется в файле views.py для вывода в шаблон приложения.

 

Практика

Файл models.py

Сначала нам нужно создать таблицу постов с полями, для этого нужно открыть файл blog/models.py и создать там класс таблицы постов с полями

from django.db import models
from django.shortcuts import reverse

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=150, db_index = True)
    slug = models.SlugField(max_length=150, unique = True)
    body = models.TextField(blank=True, db_index = True)
    date_pub = models.DateTimeField(auto_now_add = True)
    
    def get_absolute_url(self):
        return reverse('post_detail_url', kwargs={'slug': self.slug})
    
    def __str__(self):
        return '{}'.format(self.title)
        

Класс Post имеет 6 членов. 4 свойства и 2 — метода:

  • title — поле заголовка;
  • slug — поле URL;
  • body — поле текста;
  • date_pub — поле даты;
  • get_absolute_url() — абсолютный URL на текущий пост;
  • __str__() — переопределение объекта на вывод нужного значения.

Значения полям устанавливаются при помощи объекта models, который реализует при помощи методов функционал ORM. В данном примере используются 4 видов данных:

  • models.CharField(…) — значение символьного поля;
  • models.SlugField(…) — значение поля постоянной ссылки;
  • models.TextField(…) — значение многострочного поля;
  • models.DateTimeField(…) — значение поля даты и времени.

Когда модель таблицы в виде класса готова, то самое время наложить эту модель на реальную БД и этим занимается процесс миграции Django. Миграция состоит из 2-х шагов операций и команд:

  • makemigrations — который отвечает за создание новых миграций на основе изменений, внесенных вами в ваши модели. После этой команды в корневой папке приложения, где есть изменения в моделях появится папка migrations, в которой будут все нужные файлы для дальнейшего их отражения в БД;
  • migrate — который несет ответственность за применение и неприменение миграций.

В консоли это выглядит так

python3 manage.py makemigrations
python3 manage.py migrate

 

После миграций можно эксперементировать в  консоли с работой с созданной БД. Для входа в консоль shell можно выполнить команду

python3 manage.py shell

После данной команды консоль будет принимать уже команды python через >>> в пределах текущего проекта.

Некоторые команды работы с БД:

  • p=Post(title=’New post title 1′, slug = ‘new-post-1’, body = ‘Body text 1 …’) — заполнение нового экземпляра(строки) таблицы;
  • p.save() — сохранение экземпляра(строки) таблицы;
  • p.id — вывод какой-либо колонки(ID, к примеру);
  • print(p) — выведет то, что мы переопределили в методе __str__(self);
  • dir(p) — вывод всех свойств и методов, доступных у экземпляра строки;
  • p1=Post.objects.create(title=’New post title 2′, slug = ‘new-post-2’, body = ‘Body text 2 …’) — заполнение нового экземпляра(строки) таблицы через метода объекта;
  • Post.objects.all() — получение списка всех экземпляров(строк) в таблице;
  • Post.objects.get(slug__iexact = ‘new-post-1’) — получение какого-то экземпляра(строки) через регистронезависимую выборку;
  • Post.objects.filter(slug__contains = ‘new’) — выборка через фильтр.

Пример работы в консоли

>>> from blog.models import Post
>>> p=Post(title='New post title 1', slug = 'new-post-1', body = 'Body text 1 ...')
>>> p
<Post: New post title 1>
>>> p.id
>>> p.save()
>>> p.id
1
>>> p.id
1
>>> print(p)
New post title 1
>>> p
<Post: New post title 1>
>>> dir(p)
['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_check_column_name_clashes', '_check_field_name_clashes', '_check_fields', '_check_id_field', '_check_index_together', '_check_indexes', '_check_local_fields', '_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers', '_check_model', '_check_model_name_db_lookup_clashes', '_check_ordering', '_check_property_name_related_field_accessor_clashes', '_check_single_primary_key', '_check_swappable', '_check_unique_together', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 'body', 'check', 'clean', 'clean_fields', 'date_error_message', 'date_pub', 'delete', 'from_db', 'full_clean', 'get_deferred_fields', 'get_next_by_date_pub', 'get_previous_by_date_pub', 'id', 'objects', 'pk', 'prepare_database_save', 'refresh_from_db', 'save', 'save_base', 'serializable_value', 'slug', 'title', 'unique_error_message', 'validate_unique']
>>> p1=Post.objects.create(title='New post title 2', slug = 'new-post-2', body = 'Body text 2 ...')
>>> p1
<Post: New post title 2>

>>> Post.objects.all()
<QuerySet [<Post: New post title 1>, <Post: New post title 2>]>

>>> p1=Post.objects.create(title='New post title 3', slug = 'new-post-3', body = 'Body text 3 ...')
>>> p1=Post.objects.create(title='New post title 4', slug = 'new-post-4', body = 'Body text 4 ...')
>>> p1=Post.objects.create(title='New post title 5', slug = 'new-post-5', body = 'Body text 5 ...')
>>> p1=Post.objects.create(title='New post title 6', slug = 'new-post-6', body = 'Body text 6 ...')
>>> p1=Post.objects.create(title='New post title 7', slug = 'new-post-7', body = 'Body text 7 ...')

>>> Post.objects.get(slug__iexact = 'new-post-1')
<Post: New post title 1>
>>> Post.objects.filter(slug__contains = 'new')
<QuerySet [<Post: New post title 1>, <Post: New post title 2>, <Post: New post title 3>, <Post: New post title 4>, <Post: New post title 5>, <Post: New post title 6>, <Post: New post title 7>]>
>>>

 

Файл views.py

Файл views.py является связующим звеном между моделью и шаблоном. Открываем файл blog/views.py  редактируем. Обновления в файле выделены

from django.shortcuts import render
from django.http import HttpResponse
from .models import Post
# Create your views here.
def posts_list(request):
    posts = Post.objects.all()
    return render(request, 'blog/index.html', context = {'posts' : posts})
    #return HttpResponse("<h1>Hello! Hello!</h1>")
    
def post_detail(request, slug):
    post = Post.objects.get(slug__iexact = slug)
    return render(request, 'blog/post_detail.html', context = {'post' : post})

До этого мы грузили все посты из списка, теперь грузим из реального БД в виде posts_list(), а видом отдельного активного поста будет заниматься метод post_detail().

Файл urls.py

Открываем blog/urls.py существующему списку URL добавляем новы шаблон, по которому будет открываться отдельный пост. причем, в данном случае, в параметре slug будет хранить URL — поста. Этот параметр указан в угловых скобках, это означает на то, что оно будет переменной и попадется вторым параметром в метод вида, а в виде уже по этому уникальному slug будет сделана выборка из БД, данные которого потом через контекст передачи данных попадет в шаблон открытого поста

from django.urls import path
from .views import *

urlpatterns = [
    path('', posts_list, name='posts_list_url'),
    path('<str:slug>', post_detail, name='post_detail_url'),
]

Файлы шаблонов

Открываем blog/templates/blog/index.html переписываем

{% extends 'blog/base_blog.html'%}
{% block title %}
	Site Blog
{% endblock %}
{% block content %}
	<div>
		<div class="grid-x">
		    {% for post in posts %}
			    <div class="cell small-12 medium-3 large-3">
				      <div class="card">
					        <img src="https://foundation.zurb.com/sites/docs/assets/img/generic/rectangle-1.jpg">
					        <div class="card-section">
					        	<h4>{{ post.title }}</h4>
					          	<p>{{ post.body | truncatewords:15 }}</p>
								<!-- <a href="{% url 'post_detail_url' slug=post.slug %}" class="button">Learn More</a> -->
								<a href="{{ post.get_absolute_url }}" class="button">Learn More</a>
								<h6>{{ post.date_pub }}</h6>
					        </div>
				      </div>
			    </div>
			{% endfor %}
		</div>
	</div>
{% endblock %}

Создаем новый файл blog/templates/blog/post_detail.html и вставляем

{% extends 'blog/base_blog.html'%}
{% block title %}
	Site Blog
{% endblock %}
{% block content %}
	<div>
		<div class="grid-x">
		    <div class="cell medium-1 large-2">
		    <div class="cell small-12 medium-5 large-4">
			      <div class="card">
				        <img src="https://foundation.zurb.com/sites/docs/assets/img/generic/rectangle-1.jpg">
				        <div class="card-section">
				        	<h4>{{ post.title }} <b>{{ post.date_pub }}</b></h4>
				          	<p>{{ post.body}}</p>
				        </div>
			      </div>
		    </div>
		    <div class="cell medium-1 large-2">
		</div>
	</div>
{% endblock %}