Django - 在一对多关系中更改相关对象的值

问题描述:

我有一个表示财务模型的Django模型。该模型与另一组包含财务数据的模型有一对多的关系。在我的数据库中,我将这些值存储在美元($)中,但是当我使用这些模型时,我希望能够在欧元和英镑之间进行转换。Django - 在一对多关系中更改相关对象的值

因此,我在我的模型中添加了一个名为convert_to_ccy(rate)的方法,如果我调用它,我希望它也转换相关模型(通过此一对多关系)。这是一个非常简单的例子来说明我正在尝试做什么。

class main_model_example(models.Model): 

    INCLUDE_IN_CCY_CONVERSION = ['value_field_1', 'value_field_2' etc...] 

    # FIELD DEFINITIONS 
    date = models.DateField() 
    value_field_1 = models.DecimalField(max_digits=20, decimal_places=2, default=0.00) 
    value_field_2 = models.DecimalField(max_digits=20, decimal_places=2, default=0.00) 
    ...etc... 

    # METHODS 
    def convert_to_ccy(self, rate): 
    """Converts $ fields""" 
     for field in self._meta.get_all_field_names(): 
      if field in self.INCLUDE_IN_CCY_CONVERSION: 
       value = getattr(self, field) 
        if value != None: 
        setattr(self, field, float(value)/rate) 

     # NOW CONVERT THE RELATED MODELS 
     for position in self.the_related_model_set.all(): 
      position.convert_to_ccy_rate(rate) 


# THE RELATED MODEL 
class the_related_model(models.Model): 

    INCLUDE_CCY_CONVERSION = ['yet_another_finacial_field'] 

    main_model_example = models.ForeignKey(main_model_example, on_delete=models.CASCADE) 
    yet_another_financial_field = models.DecimalField(max_digits=20, decimal_places=2, default=0.00) 
    ...and so on.... 

    def convert_to_ccy(self, rate): 
    """Converts $ fields""" 
     for field in self._meta.get_all_field_names(): 
      if field in self.INCLUDE_IN_CCY_CONVERSION: 
       value = getattr(self, field) 
        if value != None: 
        setattr(self, field, float(value)/rate) 

这个工作,并转换正确的领域。在我的代码(views.py等)中,我传递了保留我设置的新值的主模型(即以欧元)。但是,当我再次从相关模型中获取信息时(通过使用model.the_related_model_set.all()的主模型,这些值重新变为USD。我假设这是因为xxx_set.all()方法再次从数据库中检索模型(尚未更新),我想要的是一旦我更新了相关模型,让它们留在内存中,所以当我再次使用它们时,保留更新后的值。一套我已经阅读文档和浏览的问题,但似乎无法找到类似的话

所以我有两个问题:

  1. 我想实现的是什么? I.e更新内存中的相关(一对多)模型,传递主模型(进行更多计算),然后在稍后再次参考相关模型时获取更新值。

或者是否需要将所有相关模型从主模型上取下并将它们分配给我必须通过主模型传递的变量?

  1. 事实上,我这样做是不好的?即有主模型方法调用相关模型的方法?我对我的实施并不太舒服,这常常表明有更好的方法。

任何意见,以更好的方式来实现这一点,将不胜感激。

谢谢。

+0

不知道的错误,但不会要保持各自的货币价值,只有当你想显示做转换用户?如果您现在有欧元物品并将其转换为美元,那么明天当美元价值发生变化时,您的数据库信息不正确。 – flakes

+0

是的,很好的问题。对不起,如果我不清楚。因此,我只会在向用户展示时进行转换 - 例如,当用户单击“查看报告”时,我将数据从数据库中提取出来(以美元为单位进行预先计算),获取当前汇率,转换为欧元,然后向用户展示(通过我标记的一些额外计算)。该数据库仅以美元填充。现在,我可以编写一个自定义过滤器来在模板一侧进行转换,但由于我在报告中显示的字段数量很多(几十个和几十个),因此我觉得在视图方面最好这样做。 – rioubenson

+1

值得一提的是,当我进行货币转换时,我不希望它传播到数据库。 – rioubenson

对不起,但我有困难的时候跟在你的榜样;尽管我认为这是你想要的。

一个django Queriest有一个.update()方法,可以传递新的属性来更新,并且值将会持续。

my_django_class.objects.all().update(my_class_attr=new_value) 

要获得您的查询设置,您可以在查询中使用相关名称。 Django默认生成它们,但我发现最好明确地定义它们。这This stack question addresses them well

这样一来,你的方法是这样的(如果我读它的权利):

def _update_currancies(self): 
    Some_other_model(_the_related_name__field = main_model).update(attr = new_value) 

,我觉得这是更好,当一个请求触发不更新表。通常,我只需添加两个其他字段,并且每次输入值更改(本例中为USD)时,都可以使用方法更新附加字段(可以通过覆盖保存方法来完成)。

您的情况下,它应该是这样的:

class main_model_example(models.Model): 
    us_number = models.DecimalField(max_digits=20, decimal_places=2, default=0.00) 
    eur_number = models.DecimalField(max_digits=20, decimal_places=2, default=0.00) 
    ccy_number = models.DecimalField(max_digits=20, decimal_places=2, default=0.00) 

    def _update_currancies(self): 
     #update and set new currency values 
     #e.g. self.eur_number = self.us_number * .96 

    def save(self, *args, **kwargs): 
     self._update_currancies() 
     super(main_model_example, self).save(*args, **kwargs) 
+0

嗨,尼克。感谢你的回答。如果你发现很难遵循我的例子,那么就加强这一事实,即我可能做错了/复杂的事情。我了解您的回复,但问题是我不想在美元兑换为其他货币时坚持更改。转换为其他货币仅用于向用户呈现的结束报告。所以我想要做的就是更新主模型实例和相关模型上的值(通过一对多关系),因为我将它从视图传递到模板,但不会触及底层数据。 – rioubenson

+1

我明白了。在这种情况下。我会用django-Tastypie。它是一个通常用于编写django项目和更多API的库。您可以覆盖模型资源的脱水方法,以实时生成新货币,而不会触及您的实际数据库。 –