使用属性名称列表自动创建带有`IntegerField()`字段的Django模型。

huangapple go评论56阅读模式
英文:

Automating the creation of a Django model with `IntegerField()` fields from a list of attribute names

问题

以下是您要翻译的内容:

I do have a list of attributes (field names) a model should have. This list contains about 170 entries. The field type of all of them will be IntegerField().

I now want to generate a model from this list. So something like:

class MyModel(models.Model):

    field_name1 = IntegerField()
    field_name2 = IntegerField()
    ...

but automated by code.

For this I tried the following code:

a_list_of_attr_names = ["field1", "field2", "field3"]

MyModel = type("My Model", (models.Model,), {attr_name: models.IntegerField() for attr_name in a_list_of_attr_names})

which gave me following error:

  File "D:\Users\Me\Documents\dev\project\venv\Lib\site-packages\django\db\models\base.py", line 105, in __new__
    module = attrs.pop("__module__")
             ^^^^^^^^^^^^^^^^^^^^^^^
KeyError: '__module__'

So is there another way to create a model from a list of field names?

The background of my question is, that I want to replicate the scheme of the Bundeslebensmittelschlüssel. Basicly this is a database containing hundreds of food items with their corresponding nutritions, vitamins and so on. The nutritions stored in this database for each food item are listed in the linked table. Each entry in this table has the following fields:

short, description, type, length and unit.

Example for the energy of an food item:

short= "GCAL", description= "Energie (Kilokalorien)", type= "Nu", length= 3, unit= "kcal/100 g"

So when I add a new FoodItem to my database I want it to have fields for all of the nutritions, and I want to be able to give them values. So as the database sheme of the Bundeslebensmittelschlüssel is more or less fixed I first thought about just adding all the nutritions as IntegerFileds to my FoodItem model. As I did not want to do it all by hand, I made a list off all the nutritions and asked for the locals() method. Also, my list actually is a list of dicts for all nutritions so that I can reference for example the unit of an nutrition from my views aswell.

[{"id": 4, "short": "GCAL", "description": "Energie (Kilokalorien)", "type": "Nu", "length": 3, "unit": "kcal/100 g"},
    {"id": 5, "short": "GJ", "description": "Energie (Kilojoule)", "type": "Nu", "length": 4, "unit": "kJ/100 g"},]

But thinking of it I am not sure if this is the right way to do this. So I also tried to do it all by models.

class FoodItem(models.Model):
    name = models.CharField(max_length=255)

class Nutrition(models.Model):
    short = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    type = models.CharField(max_length=255)
    length = models.IntegerField()
    unit = models.CharField(max_length=255)

class NutritionDetail(models.Model):
    nutrition = models.ForeignKey(
        Nutrition, on_delete=models.CASCADE, related_name='nutritions_details')
    composition = models.ForeignKey(
        FoodItem, on_delete=models.CASCADE, related_name='nutritions_details')
    value = models.IntegerField()

I created all the nutrition entrys from the Bundeslebensmittelschlüssel as Nutrition objects in my database. But then when I create a new FoodItem, I need to create a new NutritionDetail object for every Nutrition object in my database. And if the Bundeslebensmittelschlüssel would change, maybe they drop a nutrition or add alergenes or anything, I can add those entries to my Nutritions but I would need to add all new entries to my existing FoodItem manually.

And at the moment I am just confused if I would need to create the NutritionDetails in my views.py or admin.py when creating a new FoodItem or can I automaticly create NutritionDetails for each Nutrition in my database in my models throug an __init__ function in FoodItem? Or is the method with the static fields in FoodItem the way to go?

I am confused...

英文:

I do have a list of attributes (field names) a model should have. This list contains about 170 entries. The field type of all of them will be IntegerField().

I now want to generate a model from this list. So something like:

class MyModel(models.Model):

    field_name1 = IntegerField()
    field_name2 = IntegerField()
    ...

but automated by code.

For this I tried the following code:

a_list_of_attr_names = ["field1", "field2", "field3"]

MyModel = type("My Model", (models.Model,), {attr_name: models.IntegerField() for attr_name in a_list_of_attr_names})

which gave me following error:

  File "D:\Users\Me\Documents\dev\project\venv\Lib\site-packages\django\db\models\base.py", line 105, in __new__
    module = attrs.pop("__module__")
             ^^^^^^^^^^^^^^^^^^^^^^^
KeyError: '__module__'

So is there another way to create a model from a list of field names?


The background of my question is, that I want to replicate the scheme of the Bundeslebensmittelschlüssel. Basicly this is a database containing hundreds of food items with their corresponding nutritions, vitamins and so on. The nutritions stored in this database for each food item are listed in the linked table. Each entry in this table has the following fields:

short, description, type, length and unit.

Example for the energy of an food item:

short= "GCAL", description= "Energie (Kilokalorien)", type= "Nu", length= 3, unit= "kcal/100 g"

So when I add a new FoodItem to my database I want it to have fields for all of the nutritions, and I want to be able to give them values. So as the database sheme of the Bundeslebensmittelschlüssel is more or less fixed I first thought about just adding all the nutritions as IntegerFileds to my FoodItem model. As I did not want to do it all by hand, I made a list off all the nutritions and asked for the locals() method. Also, my list actually is a list of dicts for all nutritions so that I can reference for example the unit of an nutrition from my views aswell.

[{"id": 4, "short": "GCAL", "description": "Energie (Kilokalorien)", "type": "Nu", "length": 3, "unit": "kcal/100 g"},
    {"id": 5, "short": "GJ", "description": "Energie (Kilojoule)", "type": "Nu", "length": 4, "unit": "kJ/100 g"},]

But thinking of it I am not sure if this is the right way to do this. So I also tried to do it all by models.

class FoodItem(models.Model):
    name = models.CharField(max_length=255)

class Nutrition(models.Model):
    short = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    type = models.CharField(max_length=255)
    length = models.IntegerField()
    unit = models.CharField(max_length=255)

class NutritionDetail(models.Model):
    nutrition = models.ForeignKey(
        Nutrition, on_delete=models.CASCADE, related_name='nutritions_details')
    composition = models.ForeignKey(
        FoodItem, on_delete=models.CASCADE, related_name='nutritions_details')
    value = models.IntegerField()

I created all the nutrition entrys from the Bundeslebensmittelschlüssel as Nutrition objects in my database. But then when I create a new FoodItem, I need to create a new NutritionDetail object for every Nutrition object in my database. And if the Bundeslebensmittelschlüssel would change, maybe they drop a nutrition or add alergenes or anything, I can add those entries to my Nutritions but I would need to add all new entries to my existing FoodItem manually.

And at the moment I am just confused if I would need to create the NutritionDetails in my views.py or admin.py when creating a new FoodItem or can I automaticly create NutritionDetails for each Nutrition in my database in my models throug an __init__ function in FoodItem? Or is the method with the static fields in FoodItem the way to go?

I am confused...

答案1

得分: 0

以下是翻译好的部分:

可能的想法是与以下内容一起工作:

<pre><code>a_list_of_attr_names = ['field1', 'field2', 'field3']

class MyModel(models.Model):
    for item in a_list_of_attr_names:
        <b>locals()[item]</b> = models.IntegerField()</code></pre>

话虽如此,如果您需要使用字段名称列表,通常意味着出现了问题,因此可能建模不正确。

请注意,这不会动态更改,因此每次添加项目时,您都需要进行迁移并正确迁移。
英文:

an idea might be to work with:

<pre><code>a_list_of_attr_names = ['field1', 'field2', 'field3']

class MyModel(models.Model):
for item in a_list_of_attr_names:
<b>locals()[item]</b> = models.IntegerField()</code></pre>

That being said, if you need to work with a list of field names, you usually do something wrong, and thus likely the modeling is incorrect.

Note that this will not change dynamically, so each time you add an item, you will need to make a migration and properly migrate.

huangapple
  • 本文由 发表于 2023年5月28日 17:51:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76350877.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定