Python 以编程方式指定Django模型属性

Python 以编程方式指定Django模型属性,python,django,django-models,Python,Django,Django Models,我想以编程方式向Django模型添加属性。在类创建时(定义模型类时)。在运行时中,模型不会在这之后更改。例如,假设我想定义一个Carmodel类,并在给定货币列表的情况下,为每种货币添加一个price属性(数据库列)。(此货币列表应被视为不会在运行时更改的常量。我不希望这些价格有相关的模型。) 最好的方法是什么 我有一个我认为可行的方法,但事实并非如此。这是我如何尝试的,使用上面的汽车示例: from django.db import models class Car(models.Model

我想以编程方式向Django模型添加属性。在类创建时(定义模型类时)。在运行时中,模型不会在这之后更改。例如,假设我想定义一个
Car
model类,并在给定货币列表的情况下,为每种货币添加一个
price
属性(数据库列)。(此货币列表应被视为不会在运行时更改的常量。我不希望这些价格有相关的模型。)

最好的方法是什么

我有一个我认为可行的方法,但事实并非如此。这是我如何尝试的,使用上面的汽车示例:

from django.db import models

class Car(models.Model):
    name = models.CharField(max_length=50)

currencies = ['EUR', 'USD']
for currency in currencies:
    Car.add_to_class('price_%s' % currency.lower(), models.IntegerField())
乍一看,这似乎效果不错:

$ ./manage.py syncdb
Creating table shop_car

$ ./manage.py dbshell
shop=# \d shop_car
                                  Table "public.shop_car"
  Column   |         Type          |                       Modifiers                       
-----------+-----------------------+-------------------------------------------------------
 id        | integer               | not null default nextval('shop_car_id_seq'::regclass)
 name      | character varying(50) | not null
 price_eur | integer               | not null
 price_usd | integer               | not null
Indexes:
    "shop_car_pkey" PRIMARY KEY, btree (id)
但是,当我试图创造一辆新车时,它实际上已经不起作用了:

>>> from shop.models import Car
>>> mycar = Car(name='VW Jetta', price_eur=100, price_usd=130)
>>> mycar
<Car: Car object>
>>> mycar.save()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/base.py", line 410, in save
    self.save_base(force_insert=force_insert, force_update=force_update)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/base.py", line 495, in save_base
    result = manager._insert(values, return_id=update_pk)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/manager.py", line 177, in _insert
    return insert_query(self.model, values, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/query.py", line 1087, in insert_query
    return query.execute_sql(return_id)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/sql/subqueries.py", line 320, in execute_sql
    cursor = super(InsertQuery, self).execute_sql(None)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/sql/query.py", line 2369, in execute_sql
    cursor.execute(sql, params)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/backends/util.py", line 19, in execute
    return self.cursor.execute(sql, params)
ProgrammingError: column "price_eur" specified more than once
LINE 1: ...NTO "shop_car" ("name", "price_eur", "price_usd", "price_eur...
                                                             ^
>>来自shop.models导入汽车
>>>mycar=Car(名称为大众捷达,价格为100欧元,价格为130美元)
>>>我的车
>>>我的车
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
保存中的文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/models/base.py”,第410行
self.save_base(强制插入=强制插入,强制更新=强制更新)
save_base中的文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/models/base.py”,第495行
结果=管理器。\u插入(值,返回\u id=更新\u pk)
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/models/manager.py”,第177行,插入
返回insert_查询(self.model,value,**kwargs)
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/models/query.py”,第1087行,在insert_查询中
返回查询。执行sql(返回id)
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/models/sql/subquerys.py”,第320行,在execute_sql中
cursor=super(InsertQuery,self)。执行sql(无)
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/models/sql/query.py”,第2369行,在execute_sql中
cursor.execute(sql,params)
文件“/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site packages/django/db/backends/util.py”,执行中的第19行
返回self.cursor.execute(sql,params)
编程错误:多次指定“价格”列
第1行:…NTO“购物车”(“名称”、“价格”、“价格美元”、“价格欧元…”)。。。
^
显然,我的代码似乎运行了好几次,导致“price_eur”属性被添加了好几次

注释:最初我使用的措辞是“在运行时”(“我想在运行时以编程方式向Django模型添加属性。”)。这种措辞不是最好的。我真正想要的是在“模型定义时”或“类创建时”添加这些字段

“我想以编程方式向Django模型添加属性。在类创建时”

不要“以编程方式”添加列是愚蠢和令人困惑的。对于您——开发人员——来说,这似乎很好,因为您深深地理解了Django的细微差别

对于我们这些维护者来说,这些代码将(a)毫无意义,(b)必须被简单、明显的代码替换,这些代码以最简单、最明显的方式完成相同的工作

记住,维护者是知道你住在哪里的暴力反社会者。用简单明了的代码迎合他们

没有理由用一个外观复杂的循环来替换一组简单的属性定义,这既没有改进也没有节约

  • 视图函数的运行时性能相同

  • 一次性类定义保存了几行代码,这些代码在应用程序启动期间执行一次

  • 开发成本(即解决此问题)较高

  • 维护成本(即,将此代码交给其他人以保持其运行)高得惊人。只需用更简单、更明显的代码替换即可

  • 即使你有100种货币,这仍然是一个非常糟糕的主意

    “我不想要这些价格的相关型号”

    为什么不呢?相关模型(1)简单,(2)明显,(3)标准,(4)可扩展。它在运行时或开发时几乎没有可测量的成本,当然也没有复杂性

    “例如,假设我有一个汽车模型类,并希望添加一个价格属性 (数据库列)每种货币,给定货币列表。“

    这根本不是一个新属性

    这是一个表的新值(在一行中),该表以汽车型号和货币为键

    您的类看起来像这样:

    class Price( models.Model ):
        car = models.ForeignKey( Car )
        currency = models.ForeignKey( Currency )
        amount = models.DecimalField()
    
    问题的先前版本

    我希望在运行时以编程方式向Django模型添加属性


    不要这样做。在任何情况下,您都不希望“在运行时”向数据库添加属性。

    您不能在运行时这样做。这会更改数据库模型,并且通过命令
    syncdb
    更改数据库,这让人感觉非常难看


    为什么不创建第二个模型来保存不同货币的价格呢?或者如果可能的话,将价格转换成特定的货币。

    我的解决方案由于各种原因是不好的,但它是有效的:

    from django.db import models
    
    currencies = ["EUR", "USD"]
    
    class Car(models.Model):
    
        name = models.CharField(max_length=50)
    
        for currency in currencies:
            locals()['price_%s' % currency.lower()] = models.IntegerField()
    

    在我不得不这样做的地方,我可以在这样的事情和维护200多列的表之间做出选择(我知道这有多糟糕,但我对它没有影响)。

    仍然不太好,但比使用
    局部变量更好的解决方案是使用
    字段

    for currency in currencies:
        models.IntegerField().contribute_to_class(Car, 'price_%s' % currency.lower())
    
    (为此,我一直是一个非常糟糕的维护者*)

    编辑:再三考虑,您的代码运行良好(
    Car.add\u)