Este problema aparentemente inocuo resultó ser bastante difícil de encontrar información. Solo quiero disminuir el valor de una columna Integerfield en 1 en mi base de datos, llamando a una función.

llamada a la función views.py

StudentProfile.objects.add_lesson(student_id)

managers.py

class StudentQuerySet(models.QuerySet):

    def add_lesson(self, sid):          
        self.filter(student_id=sid).update(remaining_lessons=remaining - 1)

class StudentProfileManager(models.Manager):
    def add_lesson(self, sid):
        self.get_queryset().add_lesson(sid)

Modelo completo de perfil del alumno

class StudentProfile(models.Model):
    student = models.OneToOneField(
        User, related_name='student', primary_key=True, parent_link=True, on_delete=models.CASCADE)
    portrait = models.ImageField(
        upload_to='studentphotos', verbose_name=_('Student Photo'))
    about_me = models.TextField(verbose_name=_("About Me"))
    spoken_languages = models.CharField(max_length=255)
    teacher_default = models.OneToOneField(
        'teachers.TeacherProfile', related_name='teacher_default', parent_link=True, 
on_delete=models.CASCADE, default=None, blank=True, null=True)
    membership_start = models.DateTimeField(
        verbose_name="Membership Start Date", default=now, editable=False)
    membership_end = models.DateTimeField(
        verbose_name="Membership End Date", default=now, editable=False)
    remaining_lessons = models.IntegerField(
        verbose_name="Membership remaining lessons", default=0)

    objects = StudentProfileManager()

    def __str__(self):
        return User.objects.get_student_name(self.student_id)

Sé que esto está totalmente mal, cualquier ayuda es apreciada.

0
Lawrence DeSouza 28 abr. 2020 a las 05:24

3 respuestas

La mejor respuesta

Intenté usar la expresión F, y no tengo idea de por qué, pero disminuyó en 3 en lugar de en 1. Quizás Django ejecuta ese código 3 veces cuando se invoca en la vista. Encontré una solución que logra esto sin una función, en la vista, hace exactamente lo que espero, una disminución de 1:

student_id = request.user.id
student_queryset = StudentProfile.objects.get(student_id=student_id)
student_queryset.remaining_lessons = student_queryset.remaining_lessons - 1
student_queryset.save()
0
Lawrence DeSouza 28 abr. 2020 a las 04:00

Si desea mantener su configuración actual y poder add_lesson() para disminuir "resto_lessons", el cambio más pequeño que puede hacer para lograrlo es mediante la expresión F ():

from django.db.models import F

class StudentQuerySet(models.QuerySet):
    def add_lesson(self, sid):
        self.filter(student_id=sid).update(remaining_lessons=F('remaining_lessons') - 1)

Ref: https://docs.djangoproject.com/en/3.0/ref / modelos / expresiones /

Aunque personalmente creo que si su objetivo es tener un método que disminuya "resto_lessons" en 1, probablemente debería convertirlo en un método modelo. Me gusta esto:

class StudentProfile(models.Model):
    # ... your model field ...

    def add_lesson(self):
        self.remaining_lesson -= 1
        self.save()

# and in your Views.py
StudentProfile.objects.get(student_id=sid).add_lesson()

Espero que esto ayude.

0
MarkL 28 abr. 2020 a las 03:35

Django proporciona expresiones F para exactamente el tipo de tarea que tienes. Realiza la actualización en relación con el valor del campo original en la base de datos.

Debería cambiar sus managers.py de la siguiente manera (más las declaraciones return :))

from django.db.models import F

class StudentQuerySet(models.QuerySet):
    def add_lesson(self, sid):
        return self.filter(student_id=sid).update(remaining_lessons=F('remaining_lessons')-1)


class StudentProfileManager(models.Manager):
    def add_lesson(self, sid):
        return self.get_queryset().add_lesson(sid)

Podría ir aún más lejos, y por el enfoque DRY, use QuerySet.as_manager() para crear una instancia de Manager con una copia de los métodos de QuerySet personalizados en lugar de repetir el método dos veces en su Manager y QuerySet personalizados. P.ej.:

class StudentProfile(models.Model):
    ...
    objects = StudentQuerySet().as_manager()

¡Espero que ayude!

0
Inna Zhurba 28 abr. 2020 a las 03:31