Aplikacja Django korzystająca z API DRF – get()
Dziś zapraszamy na temat nieco mniej elektroniczny, a bardziej programistyczny. Dominik Bednarski zaprezentuje, w jaki sposób we frameworku sieciowym Django, z wykorzystaniem REST API można korzystać z funkcji get(). Pokaże też praktyczny przykład aplikacji pobierającej i wyświetlającej dane z sieci.
Więcej artykułów na Blogu IntHou
Wyobraźmy sobie – opowiada Dominik – że skończyliśmy prace nad naszym API lub też API jest stworzone w takim stopniu, że może być wykorzystane przez zewnętrzne aplikacje. W związku z powyższym kolejnym krokiem, jaki warto poznać, jest korzystanie z REST API stworzonego przy pomocy Django Rest Framework, poprzez zwykłą aplikację w Django. Warto w tym miejscu zaznaczyć, że przy takiej architekturze mamy w pełni oddzieloną warstwę przechowywania danych od warstwy interfejsu użytkownika.
Aplikacja Django korzystająca z API DRF – get()
W celu uproszczenia zagadnienia, gdzie aplikacja będzie korzystała z REST API, postanowiłem, aby obydwie części należały do tego samego projektu, w związku z czym, nie musimy tworzyć nowego projektu Django od nowa.
Jeżeli chcecie dowiedzieć się więcej na temat szablonów, to zachęcam do zapoznania się z pozostałymi wpisami o Django, które znajdują się na blogu inthou.pl.
W pierwszej kolejności stwórzmy szablon html o nazwie base.html.
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<link rel="shortcut icon" href="#" />
<title>REST API APP!</title>
</head>
<body>
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 class="my-0 mr-md-auto font-weight-normal">REST API APP</h5>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
{% block content %}{% endblock %}
</body>
</html>
W drugim kroku utworzymy kolejny plik html o nazwie home.html, który będzie rozszerzał plik base.html. W pliku tym będę zamieszczał wyniki pracy. Taka struktura szablonów ma celu oddzielenie części kodu, która będzie się zmieniała od części kodu, która jest stała.
{% extends 'restapiapp/base.html' %}
{% block content %}
<div class="container">
</div>
{% endblock %}
Teraz stwórzmy prostą funkcję widoku, która będzie renderowała szablon home.html. i wykorzystywała do tego dane ze słownika context.
def home(request):
context = {}
return render(request, 'restapiapp/home.html', context)
Następnie stwórzmy ścieżkę, która połączy adres URL z funkcją nowo stworzonego widoku.
urlpatterns = [
path('admin/', admin.site.urls),
# API
path('api/authors/', views.AuthorList.as_view()),
path('api/books/', views.BookList.as_view()),
path('api/borrows/', views.BorrowList.as_view()),
path('api/borrows/<int:pk>/', views.BorrowRetrieveDestroy.as_view()),
path('api/borrows/<int:pk>/return/', views.BorrowReturnBookUpdate.as_view()),
path('api/borrows/<int:pk>/edit/', views.BorrowRetrieveUpdate.as_view()),
path('api/user/create', views.UserCreate.as_view()),
path('api/user/login', views.UserTokenList.as_view()),
path('api/activate/<int:pk>/<str:s>', views.UserAccountActivation.as_view()),
# DRF
path('api-auth/', include('rest_framework.urls')),
# APP
path('', views.home, name='home'), # new
]
Na chwilę obecną może sprawdzić, czy strona ładuje się poprawnie.
Gdy wszystko do tej pory działa poprawnie, wówczas możemy przejść do właściwej części tego zadania. W pierwszej kolejności do pliku zawierającego widoki views.py zaimportujmy moduł requests.
import requests
Do słownika context dodajmy nowy klucz ‘authors‘ i przypiszmy do niego wynik następującej funkcji requests.get(‘http://127.0.0.1:8000/api/authors/’).json(). Pod tym linkiem znajdziecie więcej informacji o module requests.
def home(request):
context = {}
context['authors'] = requests.get('http://127.0.0.1:8000/api/authors/').json()
return render(request, 'restapiapp/home.html', context)
Następnie, aby zobaczyć wynik naszego zapytania, w szablonie home.html wywołajmy zmienną authors.
{% extends 'restapiapp/base.html' %}
{% block content %}
<div class="container">
{{ authors }}
</div>
{% endblock %}
Sprawdźmy jak prezentuje się nasza strona.
Jak możemy zobaczyć, dane prezentowane są w formacie json.
Teraz pójdziemy o krok dalej i wykonamy kolejne zapytanie do serwera API, aby otrzymać listę książek. Listę tę przypiszemy do klucza w słowniku o nazwie books.
def home(request):
context = {}
context['authors'] = requests.get('http://127.0.0.1:8000/api/authors/').json()
context['books'] = requests.get('http://127.0.0.1:8000/api/books/').json()
return render(request, 'restapiapp/home.html', context)
Zmodyfikujmy teraz szablon i wyświetlmy zawartość zmiennej books.
{% extends 'restapiapp/base.html' %}
{% block content %}
<div class="container">
{{ authors }}
<br><br><br><br>
{{ books }}
</div>
{% endblock %}
Sprawdźmy wynik naszej pracy.
Obecnie nie posiadamy już ograniczenia w postaci danych zwracanych tylko z jednego zapytania do API. Oznacza to, że widoki stron / aplikacji mogą zawierać dane z wielu różnych zapytań.
Teraz możecie zadawać sobie pytanie, jak dostać się do konkretnych danych w ciągu w formacie json. Jeżeli mamy zwracaną listę, to do konkretnych elementów wystarczy, gdy po kropce po prostu dodamy liczbę. W ten sposób ograniczymy się do jednego zestawu danych (można powiedzieć – jednego rekordu).
{% extends 'restapiapp/base.html' %}
{% block content %}
<div class="container">
{{ authors }}
<br><br><br><br>
{{ books }}
<br><br>
{{ books.0 }}
</div>
{% endblock %}
Sprawdźmy, jak teraz wygląda strona.
Efekt jest coraz lepszy, lecz co zrobić, aby wydobyć jedynie tytuł. W tym celu ponownie musimy zastosować kropkę i wpisać interesujący nas klucz. W tym przypadku będzie to title.
{% extends 'restapiapp/base.html’ %}
{% block content %}
<div class=”container”>
{{ authors }}
<br><br><br><br>
{{ books }}
<br><br>
{{ books.0 }}
<br><br>
{{ books.0.title }}
</div>
{% endblock %}
Ponownie sprawdźmy efekt tej modyfikacji:
Obecnie wiemy jak poruszać się po otrzymanych zbiorach danych. Sprawdźmy teraz, co się stanie, jak będziemy chcieli pobrać listę pozycji wypożyczonych borrows.
def home(request):
context = {}
context['authors'] = requests.get('http://127.0.0.1:8000/api/authors/').json()
context['books'] = requests.get('http://127.0.0.1:8000/api/books/').json()
context['borrows'] = requests.get('http://127.0.0.1:8000/api/borrows/').json()
return render(request, 'restapiapp/home.html', context)
Zmodyfikujmy odpowiednio plik home.html.
{% extends 'restapiapp/base.html' %}
{% block content %}
<div class="container">
{{ authors }}
<br><br><br><br>
{{ books }}
<br><br>
{{ books.0 }}
<br><br>
{{ books.0.title }}
<br><br><br><br>
{{ borrows }}
</div>
{% endblock %}
I sprawdźmy, co się stanie:
W tej chwili otrzymaliśmy informację, że nie jesteśmy uwierzytelnieni. Uwierzytelnianie może odbywać się na dwa sposoby. Możemy dodać do aplikacji system logowania, lecz tę funkcjonalność już pokazywałem w poprzednich wpisach a z drugiej strony, gdy stworzymy oddzielną aplikację to metoda logowania, będzie bezużyteczna.
Do dalszej części artykułu autor zaprasza na blog InThou