In Django models, the @property
decorator is used to define methods that behave like attributes, allowing you to create custom model properties. These properties can encapsulate logic and calculations, making them available as read-only attributes on model instances. Here’s how to use the @property
decorator in a Django model:
Example
Let’s say you have a Book
model with title
and author_first_name
, author_last_name
fields, and you want to create a property called author_full_name
that combines the author’s first and last names.
<span>from</span> <span>django.db</span> <span>import</span> <span>models</span><span>class</span> <span>Book</span><span>(</span><span>models</span><span>.</span><span>Model</span><span>):</span><span>title</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>100</span><span>)</span><span>author_first_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span><span>author_last_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span><span>@property</span><span>def</span> <span>author_full_name</span><span>(</span><span>self</span><span>):</span><span>return</span> <span>f</span><span>"</span><span>{</span><span>self</span><span>.</span><span>author_first_name</span><span>}</span><span> </span><span>{</span><span>self</span><span>.</span><span>author_last_name</span><span>}</span><span>"</span><span># Usage </span><span>book</span> <span>=</span> <span>Book</span><span>.</span><span>objects</span><span>.</span><span>get</span><span>(</span><span>pk</span><span>=</span><span>1</span><span>)</span><span>print</span><span>(</span><span>book</span><span>.</span><span>author_full_name</span><span>)</span> <span># Outputs: Firstname Lastname </span><span>from</span> <span>django.db</span> <span>import</span> <span>models</span> <span>class</span> <span>Book</span><span>(</span><span>models</span><span>.</span><span>Model</span><span>):</span> <span>title</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>100</span><span>)</span> <span>author_first_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span> <span>author_last_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span> <span>@property</span> <span>def</span> <span>author_full_name</span><span>(</span><span>self</span><span>):</span> <span>return</span> <span>f</span><span>"</span><span>{</span><span>self</span><span>.</span><span>author_first_name</span><span>}</span><span> </span><span>{</span><span>self</span><span>.</span><span>author_last_name</span><span>}</span><span>"</span> <span># Usage </span><span>book</span> <span>=</span> <span>Book</span><span>.</span><span>objects</span><span>.</span><span>get</span><span>(</span><span>pk</span><span>=</span><span>1</span><span>)</span> <span>print</span><span>(</span><span>book</span><span>.</span><span>author_full_name</span><span>)</span> <span># Outputs: Firstname Lastname </span>from django.db import models class Book(models.Model): title = models.CharField(max_length=100) author_first_name = models.CharField(max_length=50) author_last_name = models.CharField(max_length=50) @property def author_full_name(self): return f"{self.author_first_name} {self.author_last_name}" # Usage book = Book.objects.get(pk=1) print(book.author_full_name) # Outputs: Firstname Lastname
Enter fullscreen mode Exit fullscreen mode
Key Points
-
Read-Only: Properties created using
@property
are read-only. You cannot set them directly. If you need a writable property, you can define custom setter methods using the@property.setter
decorator. -
Calculations and Logic: You can perform calculations or other logic inside the property method to dynamically generate the attribute value.
-
Usage in Querysets: Since the property is calculated in Python and not stored in the database, you cannot directly use it in database queries. If you need to filter or sort based on such properties, you might need to use annotations or other query constructs.
Example with Setter
If you want to allow setting the author_full_name
as well, you can define a setter for the property:
<span>class</span> <span>Book</span><span>(</span><span>models</span><span>.</span><span>Model</span><span>):</span><span>title</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>100</span><span>)</span><span>author_first_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span><span>author_last_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span><span>@property</span><span>def</span> <span>author_full_name</span><span>(</span><span>self</span><span>):</span><span>return</span> <span>f</span><span>"</span><span>{</span><span>self</span><span>.</span><span>author_first_name</span><span>}</span><span> </span><span>{</span><span>self</span><span>.</span><span>author_last_name</span><span>}</span><span>"</span><span>@author_full_name.setter</span><span>def</span> <span>author_full_name</span><span>(</span><span>self</span><span>,</span> <span>full_name</span><span>):</span><span>first_name</span><span>,</span> <span>last_name</span> <span>=</span> <span>full_name</span><span>.</span><span>split</span><span>(</span><span>'</span><span> </span><span>'</span><span>,</span> <span>1</span><span>)</span><span>self</span><span>.</span><span>author_first_name</span> <span>=</span> <span>first_name</span><span>self</span><span>.</span><span>author_last_name</span> <span>=</span> <span>last_name</span><span># Usage </span><span>book</span> <span>=</span> <span>Book</span><span>.</span><span>objects</span><span>.</span><span>get</span><span>(</span><span>pk</span><span>=</span><span>1</span><span>)</span><span>book</span><span>.</span><span>author_full_name</span> <span>=</span> <span>"</span><span>NewFirstname NewLastname</span><span>"</span><span>book</span><span>.</span><span>save</span><span>()</span><span>print</span><span>(</span><span>book</span><span>.</span><span>author_first_name</span><span>)</span> <span># Outputs: NewFirstname </span><span>print</span><span>(</span><span>book</span><span>.</span><span>author_last_name</span><span>)</span> <span># Outputs: NewLastname </span><span>class</span> <span>Book</span><span>(</span><span>models</span><span>.</span><span>Model</span><span>):</span> <span>title</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>100</span><span>)</span> <span>author_first_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span> <span>author_last_name</span> <span>=</span> <span>models</span><span>.</span><span>CharField</span><span>(</span><span>max_length</span><span>=</span><span>50</span><span>)</span> <span>@property</span> <span>def</span> <span>author_full_name</span><span>(</span><span>self</span><span>):</span> <span>return</span> <span>f</span><span>"</span><span>{</span><span>self</span><span>.</span><span>author_first_name</span><span>}</span><span> </span><span>{</span><span>self</span><span>.</span><span>author_last_name</span><span>}</span><span>"</span> <span>@author_full_name.setter</span> <span>def</span> <span>author_full_name</span><span>(</span><span>self</span><span>,</span> <span>full_name</span><span>):</span> <span>first_name</span><span>,</span> <span>last_name</span> <span>=</span> <span>full_name</span><span>.</span><span>split</span><span>(</span><span>'</span><span> </span><span>'</span><span>,</span> <span>1</span><span>)</span> <span>self</span><span>.</span><span>author_first_name</span> <span>=</span> <span>first_name</span> <span>self</span><span>.</span><span>author_last_name</span> <span>=</span> <span>last_name</span> <span># Usage </span><span>book</span> <span>=</span> <span>Book</span><span>.</span><span>objects</span><span>.</span><span>get</span><span>(</span><span>pk</span><span>=</span><span>1</span><span>)</span> <span>book</span><span>.</span><span>author_full_name</span> <span>=</span> <span>"</span><span>NewFirstname NewLastname</span><span>"</span> <span>book</span><span>.</span><span>save</span><span>()</span> <span>print</span><span>(</span><span>book</span><span>.</span><span>author_first_name</span><span>)</span> <span># Outputs: NewFirstname </span><span>print</span><span>(</span><span>book</span><span>.</span><span>author_last_name</span><span>)</span> <span># Outputs: NewLastname </span>class Book(models.Model): title = models.CharField(max_length=100) author_first_name = models.CharField(max_length=50) author_last_name = models.CharField(max_length=50) @property def author_full_name(self): return f"{self.author_first_name} {self.author_last_name}" @author_full_name.setter def author_full_name(self, full_name): first_name, last_name = full_name.split(' ', 1) self.author_first_name = first_name self.author_last_name = last_name # Usage book = Book.objects.get(pk=1) book.author_full_name = "NewFirstname NewLastname" book.save() print(book.author_first_name) # Outputs: NewFirstname print(book.author_last_name) # Outputs: NewLastname
Enter fullscreen mode Exit fullscreen mode
Limitations
- Database Queries: Properties cannot be used in queryset filters or orderings. For example, you cannot do
Book.objects.filter(author_full_name="John Doe")
. - Performance: Since properties are calculated in Python, they might introduce performance overhead if used extensively on large datasets.
Using properties in Django models helps keep your code clean and encapsulate logic within the model, promoting the principles of object-oriented programming.
暂无评论内容