Mutual foo.bar and bar.foo attributes in django Models with onetooneviews - django

I have two classes, Foo and Bar, in a Django app (on AppEngine if that matters). There's a one to one relationship between them.
class Foo(BaseModel):
bar = Bar.objects.get(foo=self.id)
class Bar(BaseModel):
foo = models.OneToOneField(Foo, blank=True, null=True, help_text="Foos for this bar")
I'd like each object of both classes to have it's related object of the other class as an instance variable.
What's the best way to allow that?
When trying the code above, I'm in an odd situation: since they each refer to each other, I'm trying to use these variables before they're defined (and of course it doesn't work).
I suspect there is A Proper Way to do this, and this isn't it!

You don't need to do anything. This is the default behaviour. Just define the relationship in Bar, and Foo will automatically get a bar attribute.

Related

Using a custom manager function in a model definition

I'm trying to use manager function to populate a default field of a Model, but I'm having trouble getting it working. Here's my code:
class FooManager(models.Manager):
def foo_filter(self):
return Foo.objects.latest('id')
class Foo(models.Model):
objects = FooManager()
name = models.CharField(
max_length=100,
unique=True,
default=objects.foo_filter())
Whenever I run it,
I get NameError: global name 'Foo' is not defined on the line return Foo.objects.latest('id')
Ha! This is a cool one :)
When your models.py gets loaded for the first time, Python is trying to parse all the class definitions.
So the first thing it sees is FooManager, so far so good.
In your filter method you make use of Foo, which is still unknown at this point. Usually that would not be a problem, because you are using Foo in a method and that method only gets called during runtime, when all the classes are already loaded.
Now Python sees the Foo class and on the name field you are calling one of the manager's methods. At this point, when your filter method is called, the Foo class has not been fully loaded, yet, so when you enter the filter method, Foo is indeed not defined.
You would have to move the manager definition below the Foo definition, but you can't do that, because then the line objects = FooManager() would fail because FooManager would be undefined.
By the way: This is a very common newbie error: You must never put method calls into your field definitions. It means that the method is only executed once when the server starts and Django loads all the model definitions. This leads to extremely frustrating errors:
At first, the default value of your field is indeed the latest Foo object, but when you add a new object to the database, it will not change to the new latest object, it will stay the same object that was the latest when the server was started.
Django usually allows you to put methods into your field definitions, so you could write:
default=objects.foo_filter
without the (). Now, when the server is loaded, the method will not be executed. It will only be executed, when Django actually needs to retrieve the default value, and at that point in time, both, FooManager and Foo have already been loaded.
But apart from that, your manager doesn't even need to know which model it belongs to. Have a look at the Django docs here: https://docs.djangoproject.com/en/1.7/topics/db/managers/#modifying-initial-manager-querysets
Each manager has a get_queryset method which you can override and which you should use, so you could do the following:
class FooManager(models.Manager):
def foo_filter(self):
return self.get_queryset().latest('id')
Now your manager doesn't use the Foo class at all and you won't get into any circular dependency problems.
By the way, I don't think that latest('id') will work, you have to pass in a field name that is a date field, not an ID field.
You are create a loop, that object already is Foo.objects. All you need is:
def foo_filter(self):
return self.latest('id')
On top of that you can't use the database to set defaults for a field like that.

If you have external tasks that gather information about a model should it live in the model as a method?

For example we have a method that fetches additional information about a model from third party APIs. Is it okay to put this as a method on the model or should it live outside?
class Entity(models.Model):
name = ...
location = ...
def fetch_location(self):
# fetch the location from another server and store it.
self.location = "result"
If the data is related to the instance than it can be the right place to put it. Only if you get a lot of these you might want to wrap them in a different class for your own readability (i.e. knowing what is internal and what is external from the instance perspective).
The way I generally do it:
Manager: anything pertaining a group of Model instances
Model: anything pertaining a single Model Instance
Well, if you think in terms of Object Oriented Programming, the answer is "yes":
If "the object can do something", than it should be included as a member function (aka method).
But: If several different classes would need the same functionality (e.g. an "Entity Owner" would like to fetch the location by himself without calling my_entity.fetch_location), you should consider a (abstract) class above both classes which implements the behaviour.
If you have to call the method without an existing instance (which seems not to be the case in your example), you might consider writing the method outside of a class or you add the #staticmethod decorator which allows you to call Entity.fetch_location (remember to omit self in this case since there is no self if there is no instance.) I would prefer the staticmethod over a global method because the caller will always know, which class it relates to.
#staticmethod
def fetch_location():
# fetch the location from another server and store it.
self.location = "result"

Django ManyToMany with inheritance

I've checked a number of SO articles and I don't believe there is any way to accomplish what I want to do, but before I abandon Django I wanted to articulate the question itself and see if I missed something.
I'm implementing a graph (nodes, edges) which can contain subclasses of a base type. That is, an edge can connect a base class to a subclass, or a subclass to a subclass, etc . . . I want to be able to pull all the edges for a given object, find the objects these edges point to, and call some function on these terminal objects. I was hoping that I could call the function in a polymorphic way, but I can't figure out a way to make that happen.
class Node(models.Model):
...
def dosomething():
class SpecialNode(Node):
...
def dosomething():
class Edge(models.Model):
#yes, related_name is weird, but this seems to be what makes sense
source = models.ForeignKey(Node, related_name='targets')
target = models.ForeignKey(Node, related_name='sources')
With this structure I can do:
sourceedges = node.sources.all()
for sourceedge in sourceedges:
sourceedge.source.dosomething()
But the "dosomething" function is always called on the Node object, even if source is actually a SpecialNode object.
I've tried doing this with django_polymorphic but I don't believe this supports M2M inheritance through an Edge object (this is required for other reasons in my app).
I've tried to use contenttypes, but I think you're only allowed one generic relation per class. Edge, in other words, can't have 2 different generic relations in it.
I imagine I could establish an object called an Endpoint which would have just a single generic relation on it, then link the Edge object to it like so:
class Endpoint(models.Model)
...
content_object = generic.GenericForeignKey(...)
class Edge(models.Model)
source = models.ForeignKey(Endpoint, related_name='targets')
target = models.ForeignKey(Endpoint, related_name='sources')
But this introduces another level of indirection in my model and I start to feel like the framework is coding me rather than the other way around :)
Anyway, if someone has figured out a way to get this particular use case done, please let me know. A better way than what I suggested above would be welcome, as I currently like a lot of things I get out of the box with Django.
Thanks

Secure-by-default django ORM layer---how?

I'm running a Django shop where we serve each our clients an object graph which is completely separate from the graphs of all the other clients. The data is moderately sensitive, so I don't want any of it to leak from one client to another, nor for one client to delete or alter another client's data.
I would like to structure my code such that I by default write code which adheres to the security requirements (No hard guarantees necessary), but lets me override them when I know I need to.
My main fear is that in a Twig.objects.get(...), I forget to add client=request.client, and likewise for Leaf.objects.get where I have to check that twig__client=request.client. This quickly becomes error-prone and complicated.
What are some good ways to get around my own forgetfulness? How do I make this a thing I don't have to think about?
One candidate solution I have in mind is this:
Set the default object manager as DANGER = models.Manager() on my abstract base class(es).
Have a method ok(request) on said base classes which applies .filter(leaf__twig__branch__trunk__root__client=request.client) as applicable.
use MyModel.ok(request) instead of MyModel.objects wherever feasible.
Can this be improved upon? One not so nice issue is when a view calls a model method, e.g. branch.get_twigs_with_fruit, I now have to either pass a request for it to run through ok or I have to invoke DANGER. I like neither :-\
Is there some way of getting access to the current request? I think that might mitigate the situation...
Ill explain a different problem I had however I think the solution might be something to look into.
Once I was working on a project to visualize data where I needed to have a really big table which will store all the data for all visualizations. That turned out to be a big problem because I would have to do things like Model.objects.filter(visualization=5) which was just not very elegant and not efficient.
To make things simpler and more efficient I ended up creating dynamic models on the fly. Essentially I would create a separate table in the db on the fly and then store a data only for that one visualization in that. My code is something like:
def get_model_class(table_name):
class ModelBase(ModelBase):
def __new__(cls, name, bases, attrs):
name = '{}_{}'.format(name, table_name)
return super(ModelBase, cls).__new__(cls, name, bases, attrs)
class Data(models.Model):
# fields here
__metaclass__ = ModelBase
class Meta(object):
db_table = table_name
return Data
dynamic_model = get_model_class('foo')
This was useful for my purposes because it allowed queries to be much faster but getting back to your issue I think something like this can be useful because this will make sure that each client's data is separate not only via a foreign key, but is actually separated in the db.
Using this method is pretty straight forward except before using the model, you have to call the function to get it for each client. To make things more efficient you can cache/memoize the results of the function call so that it does not have to recompute the same thing more than once.

Mimic remote API or extend existing django model

I am in a process of designing a client for a REST-ful web-service.
What is the best way to go about representing the remote resource locally in my django application?
For example if the API exposes resources such as:
List of Cars
Car Detail
Car Search
Dealership summary
So far I have thought of two different approaches to take:
Try to wrangle the django's models.Model to mimic the native feel of it. So I could try to get some class called Car to have methods like Car.objects.all() and such. This kind of breaks down on Car Search resources.
Implement a Data Access Layer class, with custom methods like:
Car.get_all()
Car.get(id)
CarSearch.search("blah")
So I will be creating some custom looking classes.
Has anyone encoutered a similar problem? Perhaps working with some external API's (i.e. twitter?)
Any advice is welcome.
PS: Please let me know if some part of question is confusing, as I had trouble putting it in precise terms.
This looks like the perfect place for a custom manager. Managers are the preferred method for "table-level" functionality, as opposed to "row-level" functionality that belongs in the model class. Basically, you'd define a manager like this:
class CarAPIManager(models.Manager):
def get_detail(self, id):
return self.get(id=id)
def search(self, term):
return self.filter(model_name__icontains=term)
This could be used either as the default manager -- e.g., in your model definition:
class Car(models.Model):
...
objects = CarAPIManager()
# usage
>>> Car.objects.search(...)
or you could just make it an additional manager, as a property of the class:
class Car(models.Model):
...
api = CarAPIManager()
# usage
>>> Car.api.search(...)