Django models and Python properties - python

I've tried to set up a Django model with a python property, like so:
class Post(models.Model):
_summary = models.TextField(blank=True)
body = models.TextField()
#property
def summary(self):
if self._summary:
return self._summary
else:
return self.body
#summary.setter
def summary(self, value):
self._summary = value
#summary.deleter
def summary(self):
self._summary = ''
So far so good, and in the console I can interact with the summary property just fine. But when I try to do anything Django-y with this, like Post(title="foo", summary="bar"), it throws a fit. Is there any way to get Django to play nice with Python properties?

Unfortunately, Django models don't play very nice with Python properties. The way it works, the ORM only recognizes the names of field instances in QuerySet filters.
You won't be able to refer to summary in your filters, instead you'll have to use _summary. This gets messy real quick, for example to refer to this field in a multi-table query, you'd have to use something like
User.objects.filter(post___summary__contains="some string")
See https://code.djangoproject.com/ticket/3148 for more detail on property support.

Related

Django - display value of an #property field in a filter

Good evening guys, I have the following model structure in my project:
`
class Foo(models.Model):
foo_name = models.TextField()
foo_city = models.TextField()
foo_actions = models.ManyToManyField(Action, through="FooActions")
#property
def bar(self):
response = True if FooAction.objects.filter(
foo_id=self.pk,
foo__action=Action.ACTION_NAME_PK).first() else False
return response
`
I need to bring the 'bar' field in a filter, but I'm not getting it.
I tried as follows:
Foo.objects.filter(nome="João").values("foo_city","bar")
Is it possible to bring this information this way?
PS.: Sorry for my bad english
No, it's not possible directly because #property method interacts with a model's objects it is not a field of model
the model field is a column of the data table but, #property method interacts with a model column I mean it's not part of the SQL query
but you can achieve those things using a third-party library.
refer to this PyPI package link here

Building object models around external data

I want to integrate external data into a Django app. Let's say, for example, I want to work with GitHub issues as if they were formulated as normal models within Django. So underneath these objects, I use the GitHub API to retrieve and store data.
In particular, I also want to be able to reference the GitHub issues from models but not the other way around. I.e., I don't intend to modify or extend the external data directly.
The views would use this abstraction to fetch data, but also to follow the references from "normal objects" to properties of the external data. Simple joins would also be nice to have, but clearly there would be limitations.
Are there any examples of how to achieve this in an idiomatic way?
Ideally, this would be would also be split in a general part that describes the API in general, and a descriptive part of the classes similar to how normal ORM classes are described.
If you want to use Django Model-like interface for your Github Issues, why don't use real Django models? You can, for example, create a method fetch in your model, that will load data from the remote api and save it to your model. That way you won't need to make external requests everywhere in your code, but only when you need it. A minimal example will look like these:
import requests
from django.db import models
from .exceptions import GithubAPIError
class GithubRepo(models.Model):
api_url = models.URLField() # e.g. https://api.github.com/repos/octocat/Hello-World
class GithubIssue(models.Model):
issue_id = models.IntegerField()
repo = models.ForeignKey(GithubRepo, on_delete=models.CASCADE)
node_id = models.CharField(max_length=100)
title = models.CharField(max_length=255, null=True, blank=True)
body = models.TextField(null=True, blank=True)
"""
Other fields
"""
class Meta:
unique_together = [["issue_id", "repo"]]
#property
def url(self):
return f"{self.repo.api_url}/issues/{self.issue_id}"
def fetch_data(self):
response = requests.get(self.url)
if response.status != 200:
raise GithubAPIError("Something went wrong")
data = response.json()
# populate fields from repsonse
self.title = data['title']
self.body = data['body']
def save(
self, force_insert=False, force_update=False, using=None, update_fields=None
):
if self.pk is None: # fetch on first created
self.fetch_data()
super(GithubIssue, self).save(
force_insert, force_update, using, update_fields
)
You can also write a custom Manager for your model that will fetch data every time you call a create method - GithubIssue.objects.create()
The django way in this case would be to write a custom "db" backend.
This repo looks abandoned but still can lead you to some ideas.
I would suggest to just use normal OOP principles, Polymorphism, Association etc. to get a similar feel to real models.
But I'm not sure I would try to simulate behavior as close as I could, because the ORM is specifically designed for database interaction. I would just write my custom methods.

Selecting only active records django query

In my Django project, I have an is_active boolean column in every table of my database. Every time I or the framework accesses the database, I want only the active records to show up. What is the standard way to achieve this? Certainly I don't want to check for is_active in every queries I make.
The easiest way to do this is to create a custom model manager, like this:
class OnlyActiveManager(models.Manager):
def get_queryset(self):
return super(OnlyActiveManager, self).get_queryset().filter(is_active=True)
Then, add it to your models:
class MyModel(models.Model):
objects = models.Manager()
active = OnlyActiveManager()
Next, use it like this:
foo = MyModel.active.all()
You can also use it to replace the default manager (called objects), but then you'll have to do custom queries to get all records that are in-active.
You can write a manager class for your model, A sample model manager is given below, for more you can refer Django official website
class MediaManager(models.Manager):
def get_queryset(self):
return MediaQuerySet(self.model, using=self._db)
def active(self):
return self.filter(is_active=True)
class Media(models.Model):
(..model fields..)
objects = MediaManager()
The query should be like
media = Media.objects.active()
you can do it by using django model managers.
please check django documentaion for detail django documentaion

Django Models - get descendants in table with relationship to self

Given the the following model:
class Item(models.Model):
name = models.CharField(max_length = 45)
belongsTo = models.ManyToManyField("self", symmetrical=False, related_name='parentOf')
def get_descendants(self):
"Returns items descendants"
pass
How would I implement the get_descendants function to get something similar to the following for n descendants:
Item.objects.filter(belongs_to=item).filter(belongs_to__belongs_to=item).filter(...)
You might want to look into Django-MPTT : http://django-mptt.github.io/django-mptt/overview.html especially the model methods it has : http://django-mptt.github.io/django-mptt/models.html#mpttmodel-instance-methods
It offers everything you would be needing in order to manipulate such relationship, I've used it in a few projects involving models similar to yours and it is quite simple to use.
If you don't want to use any third party app, then a loop returning a queryset of objects seems to be a way to deal with this.

Using Property to duck type two models

I have a django model that can have one of two objects related to it via foreign key (call them object1 and object2). The two other classes are functionally almost identical, but contain slightly different information. At the suggestion of another StackOverflow question, I am using the python method property() to set and get whichever object is present. It looks like the following:
class Master(models.Model):
object1=models.ForeignKey(Object1, null=True)
object2=models.ForeignKey(Object2, null=True)
def get_object(self):
if self.object2_id:
return self.object2
else:
return self.object1
def set_object(self, instance):
if isinstance(instance, Object2):
self.object2 = instance
self.object1 = None
else:
self.object2 = None
self.object1 = instance
objectInstance = property(get_object, set_object)
This is a simplified version of the class. I thought everything was working correctly. I was able to set, and get the information, and could display the data held in objectInstance on several of my pages. I'm using django-tables2 to display information in tables, and it too was able to show all the information. However, when I attempt to sort the data (using the convenient arrows that are provided) I get a FieldError:
FieldError at /workflow/list/request/
Cannot resolve keyword u'objectInstance' into field. Choices are: object1, object2
Any idea what's causing this? Or what snippet of code you'd need to see to help determine what the cause is?
EDIT:
So it looks like I'm not the only one with this problem. This post seems to indicate that it's a problem with django-tables2. Non-queryset data ordering in django-tables2
It seems that while the table can display information held in a property it has trouble sorting it.
If you want to use a decorator, see this response.
But the best way is using Generic relations
EDIT
Maybe that:
class Master(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
objectInstance = generic.GenericForeignKey('content_type', 'object_id')
So, you can do:
>>> t = Master(objectInstance=Object2())
>>> t.save()
>>> t.objectInstance
<Object2: a_description>
>>> t.objectInstance = Object1()
>>> t.save()
>>> t.objectInstance
<Object1: a_description>
Hope this helps!
Found an answer.
The problem was that django-tables2 didn't know how to order non-queryset data. This was solved by explicitly giving the table an order_by argument for each column.
Documentation is here: http://django-tables2.readthedocs.org/en/latest/#specifying-alternative-ordering-for-a-column

Categories