[PYTHON] Créer une API avec Django

introduction

Salut les gars! Bonjour, bonne soirée ou bonne nuit!

Salut, c'est moi. C'est Takurinton.

Cette fois, c'est comme créer une API avec Django et la frapper. En toile de fond, il y avait un problème que je ne pourrais pas mettre en œuvre sans faire quelque chose comme ça dans un certain sujet de notre université, donc j'ai l'impression que je vais le faire un peu. Eh bien, c'était assez difficile parce que j'étais dans un état d'ignorance. C'est une tâche gratuite, donc elle s'autodétruit complètement (; ∀ ;)

Conditions préalables

Temps requis

Le temps total requis était d'environ 6 heures, y compris le temps de recherche sur Google. S'il vous plaît par le guide.

Contexte

Je l'ai fait en remodelant le site EC qui a été initialement réalisé par sous-traitance. Mais je ne devrais pas détruire le site en cours de mise à jour, j'ai donc pensé qu'il serait facile de créer un autre environnement dans Docker et de créer un environnement virtuel avec docker-compose. Je pense que seule la base de données changera que vous utilisiez Docker ou non, donc j'omettrai cette partie (j'écrirai bientôt les détails sur mon blog personnel)

environnement

OS macOS Chatalina version 10.15.4
Langue Python, Java
Cadre Django REST framework

Technologie utilisée

Cliquez ici pour un lien vers l'ensemble du framework Django REST (https://www.django-rest-framework.org/)

créer! !! !!

Constitution

À l'origine, la base de données et la logique étaient solides, il n'y avait donc pas besoin de maintenance.

L'API créée cette fois acquiert les informations de commande. Comme image

Je veux obtenir le succès, alors je l'ai implémenté en conséquence.

La base de données liée à cela est la suivante.

models.py


class CustomUserManager(UserManager):
    use_in_migrations = True
    def _create_user(self, email, password=None, zip_code=None, address1=None, address2=None, address3=None,  **extra_fields):
        if not email:
            raise ValueError('L'email est obligatoire et pas de couverture')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        phone_number_regex = RegexValidator(regex=r'^[0-9]+$', message = ("Tel Number must be entered in the format: '09012345678'. Up to 15 digits allowed."))
        phone_number = models.CharField(validators=[phone_number_regex], max_length=15, verbose_name='numéro de téléphone')
        zip_code = models.CharField(max_length=8)
        address1 = models.CharField(max_length=40)
        address2 = models.CharField(max_length=40)
        address3 = models.CharField(max_length=40, blank=True)
        user.save(using=self._db)
        return email



    def create_user(self, request_data, **kwargs):
        if not request_data['email']:
            raise ValueError('Users must have an email address.')

        user = self.model(
            email=request_data['email'],
            first_name=request_data['first_name'], 
            last_name=request_data['last_name'], 
            # password=request_data['password'], 
            zip_code=request_data['zip_code'],
            address1=request_data['address1'], 
            address2=request_data['address2'], 
            address3=request_data['address3'], 
        )

        user.set_password(request_data['password'])
        user.save(using=self._db)
        return user

    def create_superuser(self, email, phone_number=None, password=None, zip_code=None, address1=None, address2=None, address3=None,  **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    #username = models.CharField(_('username'), max_length=20, unique=True)
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(_('first name'), max_length=30)
    last_name = models.CharField(_('last name'), max_length=150)
    zip_code = models.CharField(max_length=8)
    address1 = models.CharField(max_length=40)
    address2 = models.CharField(max_length=40)
    address3 = models.CharField(max_length=40, blank=True)
    phone_number_regex = RegexValidator(regex=r'^[0-9]+$', message = ("Tel Number must be entered in the format: '09012345678'. Up to 15 digits allowed."))
    phone_number = models.CharField(validators=[phone_number_regex], max_length=15, verbose_name='numéro de téléphone', null=True, blank=True)

    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_(
            'Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = CustomUserManager()
    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []


    def user_has_perm(self, user, perm, obj):
        return _user_has_perm(user, perm, obj)

    def has_perm(self, perm ,obj=None):
        return _user_has_perm(self, perm, obj=obj)
    
    def has_module_perms(self, app_label):
        return self.is_staff

    def get_short_name(self):
        return self.first_name

    class Meta:
        # db_table = 'api_user'
        swappable = 'AUTH_USER_MODEL'

class Company(models.Model):
    name = models.CharField(max_length=255)
    introduction = models.TextField(max_length=65536)
    postal_code = models.CharField(max_length=8)
    company_image = models.ImageField()
    homepage = models.CharField(max_length=255, null=True, blank=True)
    images = models.BooleanField(verbose_name='', default=False)
    place = models.CharField(max_length=255)

    def __str__(self):
        return str(self.name)


class Product(models.Model):
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    contents = models.CharField(max_length=255)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    product_image = models.ImageField()
    option = models.CharField(max_length=255, null=True, blank=True, default=None)
    price = models.IntegerField()
    def __str__(self):
        return str(self.name)

class Cart(models.Model):
    cart_id = models.IntegerField(null=True, blank=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
    is_active = models.BooleanField(default=True)
    pub_date = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return str(self.cart_id)



class UserInfomation(models.Model):
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, blank=True, null=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
    day = models.CharField(max_length=255, default=None)
    time = models.CharField(null=True, blank=True, max_length=255,  default=None)
    status = models.BooleanField(default=False, null=True, blank=True)
    total = models.IntegerField(null=True)
    remark = models.TextField(max_length=65535, null=True, blank=True)
    pub_date = models.DateTimeField(default=now)

    def __str__(self):
        return str(self.user)


class OrderItems(models.Model):
    user = models.ForeignKey(UserInfomation, on_delete=models.CASCADE)
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, blank=True, null=True)
    item = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True)
    number = models.IntegerField(null=True)
    price = models.IntegerField(null=True)
    total = models.IntegerField(null=True)

Il y a d'autres tableaux, mais cette fois je les omettrai car je peux le faire avec juste ça.

je ferai

Préparation

Tout d'abord, si vous n'avez pas installé le framework rest, installez-le.

pip install djangorestframework

Ensuite, ajoutez les paramètres suivants à settings.py.

settings.py


...  

INSTALLED_APPS = [
    ...
    'rest_framework',
]

...



JWT_AUTH = {
    'JWT_VERIFY_EXPIRATION': False, #Persistance des jetons
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}


REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),  
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),  
    'NON_FIELD_ERRORS_KEY': 'detail',
    'TEST_REQUEST_DEFAULT_FORMAT': 'json', 
    'DEFAULT_FILTER_BACKENDS': (
        'django_filters.rest_framework.DjangoFilterBackend', 
    ), 
}



Fonction de connexion

Ici, nous allons créer une fonction pour se connecter à un utilisateur existant. Cette fois, nous authentifierons toutes les demandes. Ceci est obligatoire car il permet uniquement aux utilisateurs connectés de fonctionner. Tout d'abord, créez un point de terminaison.

project_name/urls.py


from django.conf.urls import url

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    url(r'^login_/', obtain_jwt_token),
    ..., 
]

L'ajout de ce point de terminaison termine la fonction de connexion. Il est indispensable que vous construisiez une base de données. get_jwt_token renverra un jeton d'authentification lorsque vous accédez à ce point de terminaison.

Je souhaite me connecter en tant qu'utilisateur existant. J'utiliserai ipython au stade expérimental (car c'est facile)

In [1]: import requests
In [2]: import json
In [3]: data = {'email': '[email protected]', 'password': 'hogehoge'}
In [4]: r = requests.post('localhost:8000/login_/', data=data)
In [5]: print(r.json())
Out[5]: {'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5LCJ1c2VybmFtZSI6ImIxODA2NDI5QGdtYWlsLmNvbSIsImV4cCI6MTU5NDc5OTMwNCwiZW1haWwiOiJiMTgwNjQyOUBnbWFpbC5jb20ifQ.Torhy69ZyKMOOxQUUv3Ebn9V6wqSwUlsQUD5IPUaDJA'}

Un long JSON sera retourné comme ça. En guise de mise en garde pour le moment, Python a quelque chose comme json.dumps (dict) qui convertit le dictionnaire en JSON, mais si vous faites cela, vous obtiendrez une erreur. Seules les données de type dict sont transmises ici. Veuillez également conserver ce jeton retourné car vous l'utiliserez plus tard. Les données utilisées lors de la connexion sont l'adresse e-mail et le mot de passe qui sont les clés primaires. Si vous ne savez pas ce que c'est, lisez le code dans models.py.

En passant, dans les requêtes Python, vous pouvez mettre un corps dans les données et un en-tête dans les en-têtes. En utilisant r.json (), vous pouvez convertir la réponse en type dict et la convertir en un formulaire facile à utiliser. les requêtes et json sont assez denses. C'est dense. C'est dense.

JSON personnalisé

Ensuite, je retournerai le JSON personnalisé pour moi-même. Personnellement, je suis tombé ici.

Premièrement, Serializer et Generic views J'ai pensé qu'il serait préférable de l'implémenter en utilisant / generic-views / #genericapiview), mais apparemment, il s'agit d'un JSON personnalisé (ceux-ci ne peuvent renvoyer que des champs qui existent dans une seule table). Je n'arrive pas à revenir, j'ai donc changé de méthode. Il m'a fallu beaucoup de temps pour arriver à la méthode actuelle, c'est donc ma réflexion.

Si vous souhaitez renvoyer un JSON personnalisé, vous n'avez pas besoin d'un sérialiseur, alors écrivez-le directement dans views.py. Le point de terminaison est décrit dans urls.py.

urls.py



from django.urls import path
from . import views


urlpatterns = [
...
path('get_shop_view', views.ShopView.as_view()), #Ajoute ça
]

views.py



from django.http import HttpResponse
from rest_framework import generics

class ShopView(generics.ListCreateAPIView):
    # list(self, request, *args, **kwargs)Sera capable de générer du JSON personnalisé en utilisant
    def list(self, request, *args, **kwargs):
        #Liste des JSON à retourner enfin
        return_list = list()
        try:
            user_info = UserInfomation.objects.all() #Obtenez tous les utilisateurs avec une expérience d'achat
            for i in user_info:
                order = OrderItems.objects.filter(user=i) #Spécifiez l'utilisateur
                shop = order[0].item.company.name #Précisez la société

                #Obtenir la liste des produits
                order_items = dict()
                for i in order:
                    order_items[i.item.name] = {
                                                'price': i.item.price, #prix
                                                'images': str(i.item.product_image) #URL de l'image
                                                } 


                total = sum([i.total for i in order]) #montant total. Obtenez le total de la liste générée par l'inclusion de liste

                date_time_ = UserInfomation.objects.get(cart=i.cart)
                date_time = date_time_.day + date_time_.time #Obtenez le délai de livraison souhaité
                
                #Mettez ces données dans la liste complète
                return_list.append(
                    {
                        'user': str(i.user),   #Courrier de l'utilisateur
                        'shop': shop,          #Magasin où vous avez commandé
                        'order': order_items,  #Liste des produits commandés
                        'total': total,        #montant total
                        'datetime': date_time, #Délai de livraison souhaité
                    }
                )    
        #Renvoie une liste vide si une erreur se produit
        except:
            pass

        return Response(
            return_list
        )

Après avoir créé jusqu'à présent, j'enverrai une demande d'obtention au point de terminaison créé précédemment

In [1]: {'Content-Type': 'application/json',
 'Authorization': 'JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5LCJ1c2VybmFtZSI6ImIxODA2NDI5QGdtYWlsLmNvbSIsImV4cCI6MTU5NDc5OTMwNCwiZW1haWwiOiJiMTgwNjQyOUBnbWFpbC5jb20ifQ.Torhy69ZyKMOOxQUUv3Ebn9V6wqSwUlsQUD5IPUaDJA'}
In[2]: order_list = requests.get('http://localhost:8000/get_shop_view', headers=headers)
In [3]: order_list.json()
Out[3]:
[{'user': '[email protected]',
  'shop': 'Magasin B',
  'order': {'Hamburger': {'price': 1000,
    'images': 'IMG_4145_ykxb9h'}},
  'total': 1000,
  'datetime': '14 juillet 2020 Maintenant'},
 {'user': '[email protected]',
  'shop': 'Magasin B',
  'order': {'Hamburger': {'price': 1000,
    'images': 'IMG_4145_ykxb9h'},
   'curry': {'price': 2,
    'images': '11967451898714_y6tgch'}},
  'total': 2002,
  'datetime': '14 juillet 2020 Maintenant'},
 {'user': '[email protected]',
  'shop': 'Magasin B',
  'order': {'Ragoût': {'price': 11111,
    'images': 'IMG_4900_oyb5ny'},
   'Hamburger': {'price': 1000,
    'images': 'IMG_4145_ykxb9h'},
   'café': {'price': 199,
    'images': '54490_jawqyl'},
   'curry': {'price': 2,
    'images': '11967451898714_y6tgch'},
   'crêpe': {'price': 100,
    'images': 'tweet_p7chgi'},
   'Takurinton': {'price': 100,
    'images': 'npyl13'}},
  'total': 24220,
  'datetime': '16 juillet 2020 Maintenant'}]

C'est celui que j'avais mis dans le chariot à l'avance, mais il est revenu en toute sécurité! !! !! heureux ~! !! !! Jusqu'à présent, cela a pris environ 5 heures et 45 minutes. .. ..

Essayez de frapper avec Java

Étant donné que le rapport est Java, je voulais pouvoir le consulter en Java, alors je l'ai recherché sur Google et c'était étonnamment facile. Je suis un peu heureux car je pensais que c'était une langue difficile. .. .. LOL

Test.java


import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandler;
import java.nio.charset.StandardCharsets;
 
public class Test{
	public static void main(String[] args){
		try {
			HttpRequest request = HttpRequest
					.newBuilder(URI.create("http://localhost:8000/get_shop_view"))
                    .header("Content-Type", "application/json")
                    .header("Authorization", "JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5LCJ1c2VybmFtZSI6ImIxODA2NDI5QGdtYWlsLmNvbSIsImV4cCI6MTU5NDc5OTMwNCwiZW1haWwiOiJiMTgwNjQyOUBnbWFpbC5jb20ifQ.Torhy69ZyKMOOxQUUv3Ebn9V6wqSwUlsQUD5IPUaDJA")
                    .GET()
					.build();
 
			BodyHandler<String> bodyHandler = HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8);
			HttpResponse<String> response = HttpClient.newBuilder().build().send(request, bodyHandler);
            
            String body = response.body();
            System.out.println(body);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Le code est encore long, mais acceptable. Cela semble être une position d'écriture dans HttpRequest. Vous pouvez utiliser le même jeton dans l'en-tête que vous avez obtenu précédemment. Je ne comprends pas vraiment, mais ...

Compilez et exécutez.

(base) Hogehoge:working takurinton$ javac Test.java
(base) Hogehoge:working takurinton$ java Test
[{'user': '[email protected]',
  'shop': 'Magasin B',
  'order': {'Hamburger': {'price': 1000,
    'images': 'IMG_4145_ykxb9h'}},
  'total': 1000,
  'datetime': '14 juillet 2020 Maintenant'},
 {'user': '[email protected]',
  'shop': 'Magasin B',
  'order': {'Hamburger': {'price': 1000,
    'images': 'IMG_4145_ykxb9h'},
   'curry': {'price': 2,
    'images': '11967451898714_y6tgch'}},
  'total': 2002,
  'datetime': '14 juillet 2020 Maintenant'},
 {'user': '[email protected]',
  'shop': 'Magasin B',
  'order': {'Ragoût': {'price': 11111,
    'images': 'IMG_4900_oyb5ny'},
   'Hamburger': {'price': 1000,
    'images': 'IMG_4145_ykxb9h'},
   'café': {'price': 199,
    'images': '54490_jawqyl'},
   'curry': {'price': 2,
    'images': '11967451898714_y6tgch'},
   'crêpe': {'price': 100,
    'images': 'tweet_p7chgi'},
   'Takurinton': {'price': 100,
    'images': 'npyl13'}},
  'total': 24220,
  'datetime': '16 juillet 2020 Maintenant'}]

Je reviendrai en toute sécurité. React et Vue sont plus ennuyeux à cause du navigateur, mais Java est facile car il est complété sur la ligne de commande.

Résumé

En fait, il y a beaucoup de choses telles que la création d'utilisateurs, l'acquisition d'informations utilisateur, l'acquisition d'informations sur le magasin, la liste des produits que le magasin a, etc. autres que ce que j'ai écrit ici. Comme il y a de nombreuses parties ici qui dépendent d'une table, il est plus rapide de créer en spécifiant des champs que personnalisés, il est donc important de les utiliser correctement. Je suis fatigué de toucher Java, alors je vais le laisser ici aujourd'hui. LOL

De plus, j'ai pu l'implémenter en environ 6 heures, mais cela semble être un long voyage car je dois encore jouer avec de plus en plus.

Il est difficile d'obtenir toutes les tâches de la classe en ligne avec le virus corona! Voulez-vous tester! Des collégiens qui y réfléchissent! Étudions ensemble autant que le virus corona et surmontons cette situation! Je ferai de mon mieux pendant encore 2 semaines! !!

Recommended Posts

Créer une API avec Django
Créer un écran de mise à jour avec Django Updateview
[Python] Créez rapidement une API avec Flask
Créez rapidement un serveur API avec Python + Falcon
Créer un environnement avec virtualenv
Créer une page d'accueil avec django
Qiita API Oauth avec Django
Charger les modules Django avec un interpréteur
Créer Awaitable avec l'API Python / C
[AWS] Créer une API avec API Gateway + Lambda
Créez une API en utilisant hug avec mod_wsgi
Créez une tranche d'âge avec les pandas
Remarque: envoyer un e-mail avec Django
API GraphQL utilisant graphene_django dans Django
Créer un téléchargeur de fichiers avec Django
Créer une fonction d'authentification à l'aide de django-allauth et CustomUser dans Django
Créez une API Web capable de fournir des images avec Django
Créer une application Todo avec Django ① Créer un environnement avec Docker
Créez une API d'intégration sociale pour les applications smartphone avec Django
Créer une application en classifiant avec Pygame
Créer une API RESTful avec Django Rest Framework
Créez automatiquement la documentation de l'API Python avec Sphinx
Créer une visionneuse de traitement d'image avec PySimpleGUI
Créez un alias pour Route53 vers CloudFront avec l'API AWS
Parcourir une base de données externe existante avec Django
Internationalisation avec Django
Créez rapidement un fichier Excel avec Python #python
Créer une application à l'aide de l'API Spotify
Créer un environnement pour Django x Apache x mod_wsgi avec Vagrant (Ubuntu 16.04)
Création de la première application avec Django startproject
CRUD avec Django
Générer une instance Excel compatible avec les compléments avec xlwings
Créez une application de mots anglais avec python
Créer un bloc de page / Todo avec l'API Notion
Créer une API REST pour faire fonctionner dynamodb avec le Framework Django REST
Créez un fichier msi évolutif avec cx_Freeze
[AWS SAM] Créer une API avec DynamoDB + Lambda + API Gateway
Créer un programme académique avec optimisation des combinaisons
Créez une application de composition d'images avec Flask + Pillow
Créez un tableau de bord pour les appareils réseau avec Django!
Créer un environnement de Nginx + uWSGI + Python (Django) avec docker
Créer une image avec des caractères avec python (japonais)
Créez une application Hello World avec un seul fichier avec django
Comment créer une API Rest dans Django
Authentifier Google avec Django
Django 1.11 a démarré avec Python3.6
Télécharger des fichiers avec Django
Créer un planning Django
Sortie PDF avec Django
Sortie Markdown avec Django
Créez une API pour convertir des fichiers PDF en images TIF avec FastAPI et Docker
Utiliser Gentelella avec Django
Twitter OAuth avec Django
Premiers pas avec Django 1
Envoyer des e-mails avec Django
Téléchargement de fichiers avec django
Créez une application qui fonctionne bien avec les rapports des utilisateurs à l'aide de l'API COTOHA
Extruder avec l'API Fusion360
Créez des jeux avec Pygame