简体   繁体   中英

Hardcoding attributes in django models

OK here goes, this is one of those questions that makes perfect sense in my head but is difficult to explain properly :) I have a django app where I want to store records for lots of different items of equipment. Each type of equipment will have a custom model to store its attributes, such as MyEquipment below. Each type of equipment will also have a 'category', which would be useful to store as an attribute.

class Category(models.Model):
    code = models.CharField('Category', max_length=4, unique=True)
    description = models.CharField('Description', max_length=30)
    ...

class MyEquipment(models.Model):
    serial = models.IntegerField()
    ...

To save this attribute to my model I could use a foreign key to Category but I don't need to because every record in MyEquipment must be the same Category . So then I thought maybe I could hardcode the Category in the MyEquipment meta like this:

class MyEquipment(models.Model):
    serial = models.IntegerField()
    ...

    class Meta:
        category = Category.objects.get(code='EC')

But then this would rely on the Category model being populated with data to build the MyEquipment model. To me this doesn't seem best practice, using data that may or may not exist to define the structure of another model. Is there a better way I should be using to set which Category the MyEquipment model is related to?

EDIT

Thanks for the discussion below, it's made me realise perhaps I wasn't clear on my original post. So what I want to do is have a way of linking MyEquipment to a Category . So I can do something like this:

>>> from myapp.models import MyEquipment
>>> MyEquipment.CATEGORY
<Category: EC>

I want to link the whole model to a Category , so I can process each model in different ways in my view depending on which category it is. Having thought about the problem a bit more, I can get this functionality by writing MyEquipment like this:

class MyEquipment(models.Model):
    CATEGORY = Category.objects.get(code='EC')

    serial = models.IntegerField()
    ...

This way works, but is it the best way? I guess the model would do this get operation everytime the class is instantiated? Is there a more efficient method?

You can't do this anyway; the Meta class doesn't support arbitrary attributes.

The best thing would be to define this as a property, which you can access via the instance itself. To make it more efficient, you could memoize it on the class.

@property
def category(self):
    _category = getattr(self, '_category', None)
    if not _category:
        self.__class__._category = _category = Category.objects.get(code='EC')
    return _category

but ... every record in MyEquipment must be the same Category

Then you don't need any relationship. As you said already, every record in MyEquipment are same Category, why do you want to store relation in db?

UPD: Solution with model inheritance

class Place(models.Model):
    category = models.ForeignKey(Category)
    class Meta:
         abstract = True

    def save(self, *args, **kwargs):
        self.category = Category.objects.get(name=self.CATEGORY)
        return super(Place, self).save(*args, **kwargs)

class Restaurant(Place):
    ...fields...
    CATEGORY = 'RE'

class Building(Place):
    ...fields...
    CATEGORY = 'BU'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM