Niedawno zrobiłem projekt przy użyciu Django i React. wcześniej znałem Django, ale nie Reacta, co sprawiało, że radziłem sobie z drobnymi problemami podczas jego wykonywania. Przy tej okazji nauczyłem się tworzyć aplikacje w React i jak integrować React z Django. Dzielę się więc tym, czego się nauczyłem, mając nadzieję, że Ty również odniesiesz korzyści!
Stworzymy prostą aplikację, czyli Movie-Rater-App, która będzie zawierała operacje CRUD. Muszę wspomnieć, że obecnie pracuję z Django 3.0.1 i ReactJS 6.13.

Konfigurowanie Django

Na początek musimy skonfigurować nasze środowisko wirtualne. Użyję tutaj środowiska wirtualnego, upewnij się, że zainstalowałeś virtualvenv, a następnie przejdź do katalogu, w którym chcesz, aby Twój projekt się znajdował i uruchamiał:

$ pip install virtualenv
$ cd ur_project_folder

Gdy już to zrobisz, aktywuj środowisko wirtualne za pomocą:

$ virtualenv venv
$ source venv/bin/activate

Teraz będziemy musieli zainstalować kilka pakietów, w tym „Django”, „Django REST Framework” i „Nagłówki Django CORS”. DRF jest tym, co nałożymy na Django, aby zamienić nasz projekt w API, a nagłówki Django CORS są niezbędne, aby umożliwić dostęp do moich zasobów na moim interfejsie:

pip install django
pip install djangorestframework
pip install django-cors-headers

Gdy już to zrobimy, jesteśmy gotowi do stworzenia projektu Django. Uruchom następujące polecenie:

django-admin startproject movierater
django-admin startapp api
python3 manage.py runserver

Teraz przejdź do api/urls.py i wprowadź następujące modyfikacje:

#1
from django.urls import path
from rest_framework import routers
from django.conf.urls import include
router = routers.DefaultRouter()urlpatterns = [
    path('', include(router.urls)),
]

Tutaj podaję numer komentarza do każdego wykonanego przeze mnie kroku, ale opiszę kod każdego ukończonego pliku. Następnie zmodyfikuj także plikmovierater/urls.py:

from django.contrib import admin
from django.urls import path
from django.conf.urls import include # 2 new line
from rest_framework.authtoken.views import obtain_auth_token #11
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')), # 3 new line
    path('auth/', obtain_auth_token), # 11
]

Token uwierzytelniający służy do przechowywania kodu szyfrującego z nazwy użytkownika w pamięci lokalnej, dzięki czemu dane dostępowe użytkownika są zabezpieczone. następnie w projekcie MovieRater insetting.py dodaj kod jak poniżej:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', #4
    'rest_framework.authtoken',#10 make login
    'corsheaders', # to connect to front end
    'api', #4
]
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware', #cors
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Stwórzmy model określający, w jaki sposób elementy MovieRater powinny być przechowywane w bazie danych, otwórz plik movierater/models.py i zaktualizuj go za pomocą tego fragmentu:

from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
# Create your models here. 5
class Movie(models.Model):
    title = models.CharField(max_length=32)
    description = models.TextField(max_length=360)
    #9
    def no_of_ratings(self):
        ratings = Rating.objects.filter(movie=self)
        return len(ratings)
    def avg_rating(self):
        ratings = Rating.objects.filter(movie=self)
        sum = 0
        for rating in ratings:
            sum += rating.stars
        if len(ratings) > 0:
            return sum / len(ratings)
        else:
            return 0
class Rating(models.Model):
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    stars = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
    class Meta:
        unique_together = (('user', 'movie'),)
        index_together = (('user', 'movie'),)
        # do makemigrations and migrate

Powyższy fragment kodu opisuje cztery właściwości klasy Movie i trzy właściwości klasy Rating w modelu MovieRater. Następnie musimy przeprowadzić migrację i zastosować zmiany w plikach do bazy danych, zatem uruchommy następujące polecenia:

$ python3 manage.py makemigrations api
$ python3 manage.py migrate api

Możemy przetestować, czy operacje CRUD działają na modelu API Movierater, który stworzyliśmy przy użyciu interfejsu administracyjnego udostępnianego przez Django od razu po wyjęciu z pudełka, ale najpierw przeprowadzimy małą konfigurację.

Otwórz plik api/admin.py i odpowiednio go zaktualizuj:

from django.contrib import admin
from .models import Movie, Rating #6 make register
# Register your models here.
admin.site.register(Movie) #6 new line
admin.site.register(Rating) #6 new line

Utworzymy konto superużytkownika, aby uzyskać dostęp do interfejsu administratora.

$ python3 manage.py createsupersuser

możemy spróbować zalogować się pod adresem:

Następnie musimy otworzyć plik api/serializers.py i zaktualizować go następującym kodem:

#7
from rest_framework import serializers
from .models import Movie, Rating
from django.contrib.auth.models import User #14
from rest_framework.authtoken.models import Token #17
#14 for register and login
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True, 'required': True}}
        #16 validate data
        def create(self, validated_data):
            user = User.objects.create_user(**validated_data)
            Token.objects.create(user=user)
            return user
class MovieSerializer(serializers.ModelSerializer):
    class Meta:
        model = Movie
        fields = ('id', 'title', 'description', 'no_of_ratings', 'avg_rating')
class RatingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Rating
        fields = ('id', 'stars', 'user', 'movie')

utworzymy klasę widoku w api/view.py i dokonamy następujących modyfikacji:

#13
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = (AllowAny, )
# Create your views here. 7
class MovieViewSet(viewsets.ModelViewSet):
    queryset = Movie.objects.all()
    serializer_class = MovieSerializer
    authentication_classes = (TokenAuthentication, ) #12
    permission_classes = (IsAuthenticated, ) #19
    #8
    @action(detail=True, methods=['POST'])
    def rate_movie(self, request, pk=None):
        if 'stars' in request.data:
            movie = Movie.objects.get(id=pk)
            stars = request.data['stars']
            user = request.user #12
            try:
                rating = Rating.objects.get(user=user.id,
movie=movie.id)
                rating.stars = stars
                rating.save()
                serializer = RatingSerializer(rating, many=False)
                response = {'message': 'rating updated', 'result': serializer.data}
                return Response(response, status=status.HTTP_200_OK)
            except:
                rating = Rating.objects.create(user=user, movie=movie, stars=stars)
                serializer = RatingSerializer(rating, many=False)
                response = {'message': 'rating created', 'result': serializer.data}
                return Response(response, status=status.HTTP_200_OK)
        else:
            response = {'message': 'you need to provide stars'}
            return Response(response, status=status.HTTP_400_BAD_REQUEST)
class RatingViewSet(viewsets.ModelViewSet):
    queryset = Rating.objects.all()
    serializer_class = RatingSerializer
    authentication_classes = (TokenAuthentication, ) #12
    permission_classes = (IsAuthenticated, ) #19
    #20
    def update(self, request, *args, **kwargs):
        response = {'message': 'you cant update rating like that'}
        return Response(response, status=status.HTTP_400_BAD_REQUEST)
    def create(self, request, *args, **kwargs):
        response = {'message': 'you cant create rating like that'}
        return Response(response, status=status.HTTP_400_BAD_REQUEST)

Przejdź do pliku api/urls.py i dodaj go za pomocą poniższego kodu. Ten kod określa ścieżkę URL interfejsu API:

from .views import MovieViewSet, RatingViewSet, UserViewSet #8 15userviewset
router.register('movies', MovieViewSet) #8
router.register('ratings', RatingViewSet) #8
router.register('users', UserViewSet) #15 for register and login

To już ostatni krok kończący budowę API, możemy już wykonywać operacje CRUD na modelu MovieRater.

Konfigurowanie reakcji

stworzymy nasz frontend i umożliwimy mu komunikację z backendem poprzez stworzony przez nas interfejs. Następnie uruchomić:

$ npx install create-react-app movie-rater-app
$ npm start

W tym projekcie zainstalowałem i używam tej biblioteki reakcji:

Używam pliku cookie reagującego do uwierzytelniania, reagującego-fontawesome do dołączania ikony i reagującego routera-dom dla routera przeglądarki.

Stwórzmy folder komponentów, utwórz /login.js i dodaj go za pomocą poniższego kodu:
https://Gist.github.com/asaddam/7eead5c8a3c583fca165c6a348550ac1.js

Następnie zdefiniujmy niektóre formularze dla szczegółów filmu. Utwórz trzy nowe pliki w components, movieDetails.js, movieForm.js i movieList.js:

Zmodyfikujemy plik src/App.js po raz ostatni, aby zażądał danych z serwera zaplecza i zamiast tego wyświetlił je. Chcemy również mieć pewność, że wszystkie operacje CRUD wysyłają żądania do serwera zaplecza zamiast wchodzić w interakcję z danymi.

Otwórz plik i zastąp go ostateczną wersją:

Gratulacje! Właśnie pomyślnie zbudowaliśmy frontend.

Dotarliśmy do końca tego samouczka i dowiedzieliśmy się, jak skonfigurować Django i React, aby poprawnie współdziałały ze sobą.

Kod źródłowy tego samouczka jest dostępny tutaj, a aplikację możesz wypróbować tutaj:

Backend: https://github.com/asaddam/movieRaterApp-django-backend

FrontEnd: https://github.com/asaddam/movieRaterApp-React-Frontend