Résolue

Comment visé un champ dans le backend dans un model

# Orienté objet # Booléens # Django

Je me hurte sur le retour d'une fonction dans une de mes class.
Je souhaiterai remettre à zero le champ promo_date_end dans ma class lorsque que la date de la fin de promo est atteint et mettre à False le boolean promo. Voici ma class complète avec la fonction que je souhaite mettre en pratique mais je n'arrive pas trouver faire le return de celle-ci. La fonction concerné est end_promo.

class ProductMeat(models.Model):
    title = models.CharField(max_length=38, unique=True, verbose_name="Viande")
    slug = models.SlugField(max_length=38, unique=True, blank=True)
    price = models.FloatField(default=0.0, verbose_name='Prix')
    description = models.TextField(blank=True, verbose_name="Description")
    thumbnail = models.ImageField(upload_to="products", blank=True, null=True, verbose_name='Image produit')
    promo = models.BooleanField(default=False, verbose_name="Produit en promotion")
    percent = models.IntegerField(default=0, verbose_name='Pourcentage promotion')
    promo_date_end = models.DateField(blank=True, null=True, verbose_name='Date fin de promotion')

    class Meta:
        verbose_name = "Viande"

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super().save(*args, **kwargs)

    @property
    def price_with_promotion(self):
        if self.promo:
           return self.price - (self.price * self.percent / 100)
        return self.price

    def end_promo(self):
        date = datetime.today()
        datePromo = self.promo_date_end
        if datePromo == date:
            return self.promo = false && datePromo = ""

Je sais que mon return est complement raté mais je le laisse ainsi pour être plus explicite sur ce que j'essaie de trouver.

Merci encore !

Hello !

Ce que tu veux ici c'est modifier promo et promo_date_end dans ta class ProductMeat ? c'est bien ça ? Ou j'ai mal compris ?

Tes modifications ne seront pas sauvegardées dans ta base de données si tu n'appelles pas la méthode save() après.

Est ce que ça t'aide ?

Pour synthétisé ce que je souhaite réalisé, je l'ai peu être mal formulé précedement. Dans mon backend j'ai promo que je met à True pour qu'il soit affiché dans mon front avec son prix promotion et la date de la fin de promotion promo_date_end. Ce que j'essai de réalisé est quand la date de fin de promotion est atteinte promo ce met False et de mettre promo_date_end sans date dans mon backend.

Oui cela m'a aidé à voir mon ce que j'oubliais et cherché dans les vidéos mais je n'ai pas encore mis le doigt dessus. Voici ce que j'ai essayé :

1er essai :

De l'inclure dans la fonction save pour que cela sauvegarde automatiquement.

class ProductMeat(models.Model):
    title = models.CharField(max_length=38, unique=True, verbose_name="Viande")
    price = models.FloatField(default=0.0, verbose_name='Prix')
    description = models.TextField(blank=True, verbose_name="Description")
    thumbnail = models.ImageField(upload_to="products", blank=True, null=True, verbose_name='Image produit')
    promo = models.BooleanField(default=False, verbose_name="Produit en promotion")
    percent = models.IntegerField(default=0, verbose_name='Pourcentage promotion')
    promo_date_end = models.DateField(blank=True, null=True, verbose_name='Date fin de promotion')

    class Meta:
        verbose_name = "Viande"

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        date = datetime.today()
        datePromo = self.promo_date_end

        if date == datePromo:
            self.promo(default="False")
        super().save(*args, **kwargs)

    @property
    def price_with_promotion(self):
        if self.promo:
           return self.price - (self.price * self.percent / 100)
        return self.price

2e essai

Pour ce 2e essai de créé la fonction end_promo comme initialement mais en incluant la method save() mais je dois encore raté quelques choses :(

class ProductMeat(models.Model):
    title = models.CharField(max_length=38, unique=True, verbose_name="Viande")
    price = models.FloatField(default=0.0, verbose_name='Prix')
    description = models.TextField(blank=True, verbose_name="Description")
    thumbnail = models.ImageField(upload_to="products", blank=True, null=True, verbose_name='Image produit')
    promo = models.BooleanField(default=False, verbose_name="Produit en promotion")
    percent = models.IntegerField(default=0, verbose_name='Pourcentage promotion')
    promo_date_end = models.DateField(blank=True, null=True, verbose_name='Date fin de promotion')

    class Meta:
        verbose_name = "Viande"

    def __str__(self):
        return self.title

    @property
    def price_with_promotion(self):
        if self.promo:
           return self.price - (self.price * self.percent / 100)
        return self.price

    def end_promo(self):
        date = datetime.today()
        datePromo = self.promo_date_end

        if datePromo == date:
            self.promo(default="False")
        return  self.promo.save()

C'est dur de mettre en pratique ce qu'on voit en vidéo ^^

Thibault houdon

Mentor

Salut Yann !

Ton modèle est comme un objet Python et les champs que tu définis au niveau de la classe, sont des attributs d'instance une fois que tu as créé un objet dans ta base de données.

Du coup quand tu fais ça :

self.promo(default="False")

Ça ne fonctionne pas car promo est un attribut qui est égal à un booléen dans ce cas-ci (donc True ou False).

J'avoue que ce n'est pas forcément évident de comprendre les différences entre le modèle, la classe, l'instance, les champs VS les attributs une fois l'objet créé, etc.

Du coup dans ton cas il suffit de faire :

if datePromo == date:
    self.promo = False
self.save()

Le save ce fait au niveau du self directement, car tu sauvegardes l'instance et non le champ / attribut spécifiquement. Quand tu fais un save, tous les attributs que tu as modifié (comme le promo ici), seront modifiés dans la base de données.

J'espère que c'est plus clair :)

Bon...je pense ou pensais avoir compris mais mettre en pratique cela savère plus difficile. J'ai bien compris mon erreur dans les différences entre modele, classe, instance, champt et les attributs.
Pour ce nouvel essai, j'ai créé un fonction à part en utilisant @property pour l'utiliser au bon endroit dans mon template, J'ai essayé de différente maniere il doit encore me manquer un petit détail que je ne percois pas. J'ai tenté de tourner ma fonction end_promotion de plusieurs manière différentes..

Mon code HTML :

<div class="categoryPrice">
                                        {% if productMeat.promo %}
                                            <p class="price">{{ productMeat.price }} </p>
<p class="pricePromo">{{ productMeat.price_with_promotion }} </p>
<p>Fin de promotion : {{ productMeat.end_promotion }}</p>
                                        {% else %}
                                            <p class="price">{{ productMeat.price }} </p>
                                        {% endif %}
                                    </div>

Mon model avec ma nouvelle fonction :

class ProductMeat(models.Model):
    title = models.CharField(max_length=38, unique=True, verbose_name="Viande")
    price = models.FloatField(default=0.0, verbose_name='Prix')
    description = models.TextField(blank=True, verbose_name="Description")
    thumbnail = models.ImageField(upload_to="products", blank=True, null=True, verbose_name='Image produit')
    promo = models.BooleanField(default=False, verbose_name="Produit en promotion")
    percent = models.IntegerField(default=0, verbose_name='Pourcentage promotion')
    promo_date_end = models.DateField(blank=True, null=True, verbose_name='Date fin de promotion')

    class Meta:
        verbose_name = "Viande"

    def __str__(self):
        return self.title

    @property
    def price_with_promotion(self):
        if self.promo:
           return round(self.price - (self.price * self.percent / 100), 2)
        return self.price

    @property
    def end_promotion(self):
        date = datetime.today()
        datePromo = self.promo_date_end

        if  datePromo == date:
            self.promo = False
            self.save()
        else:
            return datePromo

Est-ce que ce que c'est le format de la date qui bloque ? Ou ma condition dans le HTML ? :s :s

Thibault houdon

Mentor

Salut Yann :)

Je vois ce que tu veux faire, mais utiliser une propriété n'est pas la meilleure solution ici. En fait, une propriété est juste une méthode déguisée et elle est idéale pour calculer des choses à la volée quand tu accèdes à ce champ, moins pour faire des modifications de tes objets et sauvegarder ces modifications.

Dans ton cas, tu veux que quelque chose se passe sans interaction de ta part (ou d'un utilisateur). En gros tu veux que chaque jour, toutes les instances de ProductMeat dont la date de fin de promo est aujourd'hui soient modifiées : la promo est terminée et le promo_date_end est remis à None.

Cette action correspond plus à une tâche programmée (qu'on mettrait par exemple en place avec un cron job) qu'à une propriété. Si tu utilisais une propriété, il faudrait que tu accèdes à cette propriété pour chaque produit "manuellement" pour que le code s'exécute. Ce n'est pas vraiment ce que tu veux : tu veux que ça se fasse tout seul.

Pour faire ce genre de tâches planifiées, deux options peuvent être envisagées :

  • Une commande custom Django que tu pourrais exécuter tous les jours (avec un cron job qui lance cette commande tous les jours pour faire les modifications nécessaires).

  • Tu peux regarder du côté de Celery, un package Python qui est fait pour gérer les tâches de fond et qui s'intègre bien avec Django.

C'est un peu plus compliqué que juste une propriété, mais c'est la bonne manière de faire ce genre de choses :)

Merci pour ton retour ! ^^

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.