Django – #40 – REST API cz. 15 – Aplikacja Django korzystająca z API DRF – get()
Wprowadzenie.
Wyobraźmy sobie, ż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.
Zakres artykułu.
- Aplikacja Django korzystająca z API DRF – get()
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, odchodzi nam tworzenie nowego projektu Django od nowa.
W pierwszej kolejności stwórzmy szablon html o nazwie base.html. 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.
<!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 stwórzmy 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 wpisu. 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 idźmy o krok dalej i wykonajmy kolejne zapytanie do serwera API, żebyśmy otrzymali listę książek. Listę tę przypiszmy 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 postacie 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 dobrać się do konkretnych danych w ciągu danych w formacie json. Temat ten już był poruszany w poprzednich wpisach, lecz dla przypomnienia napiszę tu jeszcze raz jak to zrobić.
Jeżeli mamy zwracaną listę, to do konkretnych elementów wystarczy, jak po kropce dodamy liczbę. W ten sposób ograniczymy się do jednego zestawu danych (można powiedzieć do 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 moim 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 otrzymamy.
W tej chwili otrzymaliśmy informację, że nie jesteśmy uwierzytelnieni. Jak pamiętacie z poprzednich wpisów, uwierzytelnianie 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.
W tym oto momencie przychodzi nam z pomocą uwierzytelnianie przy pomocy Tokena. Stwórzmy słownik o nazwie headers, dla danych wysyłanych w nagłówku zapytania. Zmienną headers zamieśćmy jako kolejny argument metody request.get(), z tym że przypiszmy go do zmiennej o tej samej nazwie.
def home(request):
context = {}
headers = {
'Authorization': 'Token 000c74d3b3b816d90e19ea42926e5a7f950366cc',
}
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()
context['borrows2'] = requests.get('http://127.0.0.1:8000/api/borrows/', headers=headers ).json()
return render(request, 'restapiapp/home.html', context)
W powyższym fragmencie kodu wartość tokena dla klucza Authorization zahardkodowałem, co jest oczywiście błędną praktyką. Token jest zmienną przypisaną do użytkownika, więc musi się zmienić w zależności, kto korzysta z aplikacji. Ponadto wartość tokena powinna być umieszczona w takim miejscu, aby nikt inny nie mógł jej podejrzeć, ponieważ dzięki temu kluczowi jest w stanie się pod nas podszywać, w zakresie takim, na jaki pozwala API
Standardowo zmodyfikujmy szablon 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 }}
<br><br>
{{ borrows2 }}
</div>
{% endblock %}
I na koniec sprawdźmy efekt naszej pracy.








