Je suis un développeur FE qui essaie de s'aventurer dans le monde de Python & Django.

Pour apprendre cela, je crée une sorte d'application de trading simulée. J'ai 2 modèles. User et UserPortfolio. Actuellement, je peux créer les deux tables indépendamment via 2 appels API différents. Cependant, j'aimerais pouvoir créer UserPortfolio lorsque User est créé. J'ai établi une relation OneToOne entre les tables.

En utilisant python, quelle est la meilleure façon d'y parvenir efficacement? Question très rapide, est-ce une bonne pratique dans Django de diviser des modèles à l'intérieur d'un projet en leurs propres fichiers?

Merci d'avance pour votre aide! :)

Dans un dossier appelé modèles, mon user.py ressemble à ceci:

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, \
                                       PermissionsMixin

from .user_portfolio import UserPortfolio                                       

class UserManager(BaseUserManager):

    def create_user(self, email, password=None, **extra_fields):
        """Creates and saves new user"""

        if not email:
            raise ValueError('Email address is required')

        user = self.model(email=self.normalize_email(email), **extra_fields)
        user.set_password(password)
        user.save(using=self._db)

        return user

class User(AbstractBaseUser, PermissionsMixin):
    """Custom user model that supports using email instead of username"""

    email = models.EmailField(max_length=255, unique=True)
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    date_of_birth = models.CharField(max_length=255)
    phone_number = models.IntegerField(null=True)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(auto_now_add=True)
    created_on = models.DateTimeField(auto_now_add=True)

    objects = UserManager()

    USERNAME_FIELD = 'email'

Dans un autre fichier user_portfolio.py, j'ai le modèle et il ressemble à ceci:

from django.db import models
from django.conf import settings

class UserPortfolioManager(models.Manager):
    """User Portfolio Manager"""
    def create_user_portfolio(self, user_id, **extra_fields):

        user_portfolio = self.model(user_id=user_id, **extra_fields)
        user_portfolio.save(using=self._db)

        return user_portfolio


class UserPortfolio(models.Model):
    """User portfolio model"""

    amount_invested = models.FloatField()
    profits = models.IntegerField(default=0)
    loss = models.IntegerField(default=0)
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )

    objects = UserPortfolioManager()

    def __str__(self):
        return 'Created!'

J'ai un fichier pour mes sérialiseurs:

from django.contrib.auth import get_user_model

from rest_framework import serializers

from core.models import UserPortfolio

class UserPortfolioSerializer(serializers.ModelSerializer):
    """Serialzier from user portfolio object"""

    class Meta:
        model = UserPortfolio
        fields =(
            'id', 
            'amount_invested',
            'profits',
            'loss',
        )
        read_only_fields = ('id',)

    def create(self, validated_data):
        print(validated_data)
        return UserPortfolio.objects.create_user_portfolio(user_id=user_id, **validated_data)

class UserSerializer(serializers.ModelSerializer):
    """Serializer for users object"""
    class Meta:
        model = get_user_model()
        fields = (
            'email',
            'password',
            'first_name',
            'last_name',
            'date_of_birth',
            'phone_number'
        )
        extra_kwargs = {'password': {'write_only': True, 'min_length': 5}}

    def create(self, validated_data):
        """Create a new user with encrypted password and return it"""
        return get_user_model().objects.create_user(**validated_data)


Et mon fichier views.py:

from rest_framework import generics, viewsets, mixins, serializers
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated

from core.models import UserPortfolio

from user.serializers import UserSerializer, UserPortfolioSerializer


class CreateUserView(generics.CreateAPIView):
    """Create new user in the system"""
    serializer_class = UserSerializer


class CreateUserPortfolioView(generics.CreateAPIView):
    serializer_class = UserPortfolioSerializer

D'après ce que je comprends actuellement, la table user_portfolio aura un user_id qui fait référence à l'utilisateur auquel appartient le portefeuille. Un portefeuille doit être unique à un utilisateur et ne peut appartenir qu’à un seul utilisateur, puis un utilisateur ne peut avoir qu’un seul portefeuille.

2
aromanarguello 12 févr. 2020 à 07:31

1 réponse

Meilleure réponse

Vous pouvez le faire en modifiant la logique dans l'un de vos sérialiseurs. Je vais changer votre UserPortfolioSerializer en quelque chose comme ci-dessous.

class UserPortfolioSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserPortfolio
        fields =(
            'id',
            'user', 
            'amount_invested',
            'profits',
            'loss',
        )
        read_only_fields = ('id',)

    def create(self, validated_data):
        user_data = validated_data.pop(user)
        user = User.objects.create_user(**user_data)
        return UserPortfolio.objects.create_user_portfolio(user=user, **validated_data)

Vous devez maintenant changer le format d'entrée comme ci-dessous:

{
    "user": {
            ....
            # user information here
            ....
            }
    ....
    # user portfolio information here
    ....
}

C'est l'idée principale pour résoudre votre problème. Je pense que vous avez compris :). Par cela, vous pouvez faire tout changement de logique à l'intérieur de votre sérialiseur.

1
dipesh 12 févr. 2020 à 04:47