LINUX.ORG.RU

реализация скидки на услуги(товар) в django

 , ,


2

2

Доброго времени суток!

Не судите строго, т.к. джанго, да и питон я начал изучать не более трех недель назад. Сейчас пытаюсь ,в качестве обучения,оптимизировать выдачу абонементов и учет занятий в студии. Подскажите, пожалуйста,:

- Как можно рассчитать итоговую цену со скидкой и записать ее в таблицу «Paiments» в поле «finish_price»? При этом данные взять из таблицы «Price», которая является внешним ключом для поля «price_of_paiment»

- Можно ли использовать «choices=» для подставления данных о скидке или лучше сделать отдельную таблицу с этими данными,т.к. данные в кортеже не будут числовыми?

На просторах интернета нашел использование функции «def get_sale(self):» которую подставил в рассчет абонемента, но так и не понял ,как туда попадут данный из поля «whole_price» для расчета и как потом записать получившийся результат в поле «finish_price».

Стоит ли дедать первичным ключем поле «whole_price», т.к. планируется не более 5 записей, и можно ли будет получить из нее данные для вычислений в таблице «Price»?

class Price(models.Model):
name_paiment = models.CharField('Название абонемента', max_length=20, unique=True)
whole_price = models.IntegerField('Цена', default=0, )
price_for_one_time = models.IntegerField('Цена за 1 посещение',)
number_of_visits = models.IntegerField('Количество посещений')

def __str__(self):
    return '%s %s' % (self.name_paiment, self.whole_price)

class Paiments(models.Model):
DISCOUNT = (
    ('0', 'нет скидки'),
    ('5', '5%'),
    ('10', '10%'),
    ('15', '15%'),
    ('20', '20%'),
    ('25', '25%'),
    ('30', '30%'),
)
paiment_of_student = models.ForeignKey(Student)
price_of_paiment = models.ForeignKey(Priсe, verbose_name='Название абонемента')
discount = models.IntegerField('Скидка в процентах', blank=True, default=0, choices=DISCOUNT) #ругается на значения, которые выбираешь.
begin_date = models.DateTimeField('Дата начала', default=timezone.now)
end_date = models.DateTimeField('Дата окончания')
finish_price = models.IntegerField(get_sale()) #пишет,что имя не определено.

def get_sale(self):
    '''Расчитать стоимость со скидкой'''
    end_price = int(self.price_of_paiment * (100 - self.discount) / 100)
    return end_price

Прошу прощения ,если где-то не правильно выразил мысль. Подскажите,как реализовать мои идеи, по возможности с кодом, т.к. просто на словах не пойму из-за неопытности.

finish_price = models.IntegerField(get_sale()) #пишет,что имя не определено.

Попробуй определить verbose_name:

finish_price = models.IntegerField('Finish price', get_sale())

discount = models.IntegerField('Скидка в процентах', blank=True, default=0, choices=DISCOUNT) #ругается на значения, которые выбираешь.

Вероятно типы не те, попроуй поменять DISCOUNT:

DISCOUNT = (
    (0, 'нет скидки'),
    (5, '5%'),
    (10, '10%'),
    (15, '15%'),
    (20, '20%'),
    (25, '25%'),
    (30, '30%'),
)

Int64 ★★★
()
Ответ на: комментарий от Int64

Да плохо прочитал пост ) понял что за get_sale, не уверен что нужно расчитаное значение хранить в таблице, можно просто исопльзовать эту функцию для расчета уже со скидкой и отображать где это необходимо

Int64 ★★★
()
Последнее исправление: Int64 (всего исправлений: 1)

Во-первых, не paiments, а payment (в единственном числе тоже). Во-вторых, я бы создал одну единственную модель - Subscription, в которой бы были поля price, discount и другие нужные тебе. Соответственно, когда нужно добавить скидку просто изменяем discount и все. И еще функцию для расчета конечной цены, которая у тебя уже есть.

creazero
()
Ответ на: комментарий от creazero

что-то наподобие этого

class Subscription(models.Model):
    price = models.IntegerField('Price', default=0)
    discount = models.IntegerField('Discount', default=0)

    ...

    def final_price(self):
        return self.price * (100 - self.discount) / 100

creazero
()
Ответ на: комментарий от Int64

У меня идея была ,чтоб в итоге можно было бы получать данные по реальным ценам всех абонементов - для расчета дохода студии за месяц. А потом в таблице с занятиями - вести учет занятий , з/плату тренеров и стоимость одного занятия. Для всего этого нет необходимости сохранять данные по скидкам в таблице?

class Lessons(models.Model):
    CLASS = (
        ('Бр', 'Брейк'),
        ('Тв', 'Твист'),
    )
    name_of_class = models.CharField('Название занятия',max_length=7, choices=CLASS)
    trainer = models.ForeignKey(Trainer, verbose_name='Тренер')
    begin_date = models.DateTimeField('Дата начала', default=timezone.now)
    end_date = models.DateTimeField('Дата окончания')
    student = models.ForeignKey(Paiments, verbose_name='Ученик')

    def __str__(self):
        return '%s %s %s' % (self.begin_date, self.name_of_class, self.trainer)

В таблицу с тренерами,кажется, надо будет добавить -стоимость одного урока тренера, чтоб з/п расчитать.

PavelShturm
() автор топика
Ответ на: комментарий от PavelShturm

Если надо это делать не часто и данных не очень много, можно и так посчитать. Но можешь добавить поле final_price и через сигналы/переопределенный save его заполнять, выше уже дали ссылку.

pawnhearts ★★★★★
()
Ответ на: комментарий от Int64

finish_price = models.IntegerField(get_sale()) #пишет,что имя не определено.

Попробуй определить verbose_name:

finish_price = models.IntegerField('Finish price', get_sale())

Попробовал , но все равно ошибка выходит с сервера:

 finish_price = models.IntegerField(save(), verbose_name='Окончательная цена' )
NameError: name 'save' is not defined
finish_price = models.IntegerField(save(), verbose_name='Окончательная цена' )


    def save(self, force_insert=True):
        '''Расчитать стоимость со скидкой'''
        end_price = int(self.price_of_paiment * (100 - self.discount) / 100)
        return end_price

Метод save ,я совсем неправильно применил?

PavelShturm
() автор топика
Ответ на: комментарий от creazero

Во-первых, не paiments, а payment (в единственном числе тоже).

Учту свои ошибки в орфографии и исправлю.

PavelShturm
() автор топика
Ответ на: комментарий от PavelShturm

Не нужно вызывать save. Этот метод сам сохраняет модель в базу данных. Тебе в нем нужно добавить нужный тебе функционал и потом вызвать save из класса-родителя:

def save(self, *args, **kwargs):
    # do something
    super(Subscription, self).save(*args, **kwargs)

И еще понятно теперь, почему у тебя и save, и get_sale is not defined. Чтобы вызывать функции класса нужно обязательно использовать self: self.get_sale()

creazero
()
Ответ на: комментарий от creazero

Создал единственную модель и перенес в нее все необходимые поля. Сразу возник вопрос - а можно ли «choices» оптимизировать, чтоб один раз выбирать и подставлялось в нужные поля? Получилось 3 почти одинаковых выбора.

class Subscription(models.Model):

    payment_of_student = models.ForeignKey(Student)
    PRICE = (
        (250, '1 посещение'),
        (900, '4 посешения'),
        (1200, '6 посещений'),
        (1600, '8 посещений'),
    )
    whole_price = models.IntegerField('Цена', default=250, choices=PRICE)
    PRICE_ONE_TIME = (
        (250, '1 посещение'),
        (225, '4 посешения'),
        (200, '6 посещений'),
        (200, '8 посещений'),
    )
    price_for_one_time = models.IntegerField('Цена за 1 посещение',default=250, choices=PRICE_ONE_TIME)
    NUMBER_OF_VISITS = (
        (1, '1 посещение'),
        (4, '4 посешения'),
        (6, '6 посещений'),
        (8, '8 посещений'),
    )
    number_of_visits = models.IntegerField('Количество посещений', choices=NUMBER_OF_VISITS)
    DISCOUNT = (
        (0, 'нет скидки'),
        (5, '5%'),
        (10, '10%'),
        (15, '15%'),
        (20, '20%'),
        (25, '25%'),
        (30, '30%'),
    )
    discount = models.IntegerField('Скидка в процентах', blank=True, default=0, choices=DISCOUNT)
    begin_date = models.DateTimeField('Дата начала', default=timezone.now)
    end_date = models.DateTimeField('Дата окончания')



    def save(self, *args, **kwargs):
        '''Расчитать стоимость со скидкой'''
        end_price = int(self.whole_price * (100 - self.discount) / 100)
        return end_price
        super(Subscription, self).save(*args, **kwargs)

    self.save() #я правильно понял, что функция запишет посчитанное в поле "end_price" в базе?

С self.save() тоже ошибка идет : NameError: name 'self' is not defined

,а без селф ,save() выдает: TypeError: save() missing 1 required positional argument: 'self'

я думал ,что self... необходимо только внутри функций указывать, когда пользуешься объектами взятыми из вне(из класса). Неверное рассуждение?

PavelShturm
() автор топика

Я бы вообще делал в поле скидки на модели не целое от 0 до 100, а десятичное от 0 до 1. Так проще запросы составлять, типа price * discount. А отображение в интерфейсе в виде процентов сделал бы своим классом поля формы.

gasinvein ★★★
()
Ответ на: комментарий от PavelShturm
finish_price = models.IntegerField(save(), verbose_name='Окончательная цена' )
    def save(self, *args, **kwargs):
        '''Расчитать стоимость со скидкой'''
        end_price = int(self.whole_price * (100 - self.discount) / 100)
        return end_price
        super(Subscription, self).save(*args, **kwargs)

Я советую немного питон подучить, прежде чем пытаться что-то делать на джанго. До строчки

super(Subscription, self).save(*args, **kwargs)
у тебя даже не дойдет, т.к. ты вызвал преждевременный выход из функции через return. Попробуй поменять на такой:
    def save(self, *args, **kwargs):
        '''Расчитать стоимость со скидкой'''
        self.end_price = int(self.whole_price * (100 - self.discount) / 100)
        super().save(*args, **kwargs)

С self.save() тоже ошибка идет : NameError: name 'self' is not defined

потому-что self используется внутри методов класса, зачем ты вообще пытаешься вызвать этот метод? метод save джанга сама будет вызывать всякий раз, когда ты будешь сохранять модель (через админку к примеру, либо у определенного экземпляра) к примеру, если я напишу так:

Subscription.objects.all().update(whole_price=100)
то у всех доступных Subscription'ов обновится поле whole_price и вызовется метод save, читай подробнее тут: https://docs.djangoproject.com/en/1.11/ref/models/querysets/

Int64 ★★★
()
Ответ на: комментарий от Int64

По твоей же ссылке:

Finally, realize that update() does an update at the SQL level and, thus, does not call any save() methods on your models, nor does it emit the pre_save or post_save signals (which are a consequence of calling Model.save()). If you want to update a bunch of records for a model that has a custom save() method, loop over them and call save()

pawnhearts ★★★★★
()
Ответ на: комментарий от Int64

Я советую немного питон подучить, прежде чем пытаться что-то делать на джанго.

Посоветуйте с чего начать? Я прочитал:www.pythontutor.ru , https://pythonworld.ru Сейчас читаю про питон на: http://younglinux.info/ . Так же прочитал на джангобук ,как первое приложение запустить. Теперь на втором пратикуюсь. Подумываю купить книги Марка Лутца.

Что еще можете посоветовать ,в качестве практики.? Понимаю ,что полный нуб:( Но есть желание научиться..

end_price = models.IntegerField('Итоговая цена'default=0)

def save(self, *args, **kwargs):
        '''Расчитать стоимость со скидкой'''
        self.end_price = int(self.whole_price * (100 - self.discount) / 100)
        super().save(*args, **kwargs)

Теперь работает! Всем огромное СПАСИБО!!!

PavelShturm
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.