Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do properties work on Django model fields?

I think the best way to ask this question is with some code... can I do this:

class MyModel(models.Model):         foo = models.CharField(max_length = 20)         bar = models.CharField(max_length = 20)        def get_foo(self):           if self.bar:               return self.bar           else:               return self.foo        def set_foo(self, input):           self.foo = input        foo = property(get_foo, set_foo)   

or do I have to do it like this:

class MyModel(models.Model):     _foo = models.CharField(max_length = 20, db_column='foo')     bar = models.CharField(max_length = 20)      def get_foo(self):         if self.bar:             return self.bar         else:             return self._foo      def set_foo(self, input):         self._foo = input      foo = property(get_foo, set_foo) 

note: you can keep the column name as 'foo' in the database by passing a db_column to the model field. This is very helpful when you are working on an existing system and you don't want to have to do db migrations for no reason

like image 898
Jiaaro Avatar asked Sep 21 '09 14:09

Jiaaro


People also ask

What is Property in Django models?

What is @property in Django? Here is how I understand it: @property is a decorator for methods in a class that gets the value in the method. But, as I understand it, I can just call the method like normal and it will get it.

When should I use @property?

You should use @property when your class attribute is formed from other attributes in the class, and you want it to get updated when source attributes are changed.

How does model work in Django?

Django web applications access and manage data through Python objects referred to as models. Models define the structure of stored data, including the field types and possibly also their maximum size, default values, selection list options, help text for documentation, label text for forms, etc.


2 Answers

A model field is already property, so I would say you have to do it the second way to avoid a name clash.

When you define foo = property(..) it actually overrides the foo = models.. line, so that field will no longer be accessible.

You will need to use a different name for the property and the field. In fact, if you do it the way you have it in example #1 you will get an infinite loop when you try and access the property as it now tries to return itself.

EDIT: Perhaps you should also consider not using _foo as a field name, but rather foo, and then define another name for your property because properties cannot be used in QuerySet, so you'll need to use the actual field names when you do a filter for example.

like image 169
Andre Miller Avatar answered Oct 07 '22 15:10

Andre Miller


As mentioned, a correct alternative to implementing your own django.db.models.Field class, one should use the db_column argument and a custom (or hidden) class attribute. I am just rewriting the code in the edit by @Jiaaro following more strict conventions for OOP in python (e.g. if _foo should be actually hidden):

class MyModel(models.Model):     __foo = models.CharField(max_length = 20, db_column='foo')     bar = models.CharField(max_length = 20)      @property     def foo(self):         if self.bar:             return self.bar         else:             return self.__foo      @foo.setter     def foo(self, value):         self.__foo = value 

__foo will be resolved into _MyModel__foo (as seen by dir(..)) thus hidden (private). Note that this form also permits using of @property decorator which would be ultimately a nicer way to write readable code.

Again, django will create _MyModel table with two fields foo and bar.

like image 45
Yauhen Yakimovich Avatar answered Oct 07 '22 15:10

Yauhen Yakimovich