For example, there are such models:
class User(Base):
photo_id = Column(ForeignKey('photo.id'))
class Group(Base):
photo_id = Column(ForeignKey('photo.id'))
class Photo(Base):
__tablename__ = 'photo'
user = relationship('User', backref='photo')
group = relationship('Group', backref='photo')
But in last model relationship to User and Group is not good because in one case first relationship will be None and in other case second relationship will be None (because photo owner can be only user or group, but not both)... And if there will be more than 2 models with foreignkeys to model Photo - situation will be even worse.
How to do such relationship correct?
Thanks in advance!
If your User and Group are not stored in the same table, there is nothing wrong to defined them with two relationship. These two relationship means two different SQL query,
and you actually needs these two different query in your case.
If your User and group can be stored in the same table, you can use inheritance.
and create a relationshop to the parent table
http://docs.sqlalchemy.org/en/latest/orm/inheritance.html
or create a view for that
http://docs.sqlalchemy.org/en/rel_0_7/core/schema.html#reflecting-views
Use table inheritance: http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/declarative.html#joined-table-inheritance
I recommend this slide to you: http://www.slideshare.net/tyler4long/quickorm . It is about quick_orm, which is base on SQLAlchemy. You will see how the same problem is resolved by means of table inheritance.
Slide 7: many models should have relationship with "comments"
Slide 8: add a parent class named "Commentable" to solve the problem.
The syntax is different from SQLAlchemy, but you can get the main idea.
I do not think there is one correct way of modeling this kind of relationships. Cardinality, navigability are also facts to consider.
To a solution very similar to your modeling problem, see Generic Associations examples. The examples might look somewhat complicated at first, but if you read Mike's blog on Polymorphic Associations with SQLAlchemy it should be pretty clear what is happening there. You will end up with somewhat different model, and navigating back from Photo to the correct parent by single attribute (parent or owner) might not be achievable, but do you really need to navigate the relationship from the side of Photo?
Related
I'm trying to figure out the best way to develop constraints around a set of models
class ParentDefinition:
child_definition = relationship()
class ChildDefinition:
parent_definition_id = ForeignKey()
class Parent:
parent_definition = relationship()
parent_definition_id = ForeignKey()
class Child:
parent = relationship()
parent_id = ForeignKey()
child_definition = relationship()
child_definition_id = ForeignKey()
I want to ensure that Child.child_definition_id == Child.parent.parent_definition.child_definition.id but I'm not sure the best way to do that.
I know that this probably isn't the best model design but there are pre-existing architecture considerations I'm working around.
Any help would be appreciated!
According to the documentation here you need to define constraint to a table or a column. As far as I know, SQL constraints can't be setup over multiple table.
If you really want to go through constraints, you can use another table that handle the association between each entities constrainable fields (ids of each items and add your constraint to id_parent_def = id_child_def).
If you don't want to create this table, you can always use listeners so you can check before inserting data but this may be inefficient for your needs.
Another way would to use database specific functions or triggers that could check conditions for you, I guess you would write plain SQL inside your migrations file to create them (or manually in your DB).
There is something that is tripping me up with models, and I guess SQL tables in general.
Let us suppose you have these models:
class Manufacturer(models.Model):
name = models.CharField()
company_created = models.CharField()
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
When you create an instance of Car like say, the following
civic = Car(manufacturer='honda')
A couple questions:
When you create an instance of Car, are you also creating an instance of Manufacturer as a by-product? Or does 'honda' need to exist as an instance already. If not, is there a way to make an instance of both, in say, one form.
Can I make calls on 'civic' for things pertaining to the manufacture? For example, could I get the 'company_created' data from the civic instance? If not, why bother having the relationship in the first place?
Thanks so much in advance. I would really appreciate a thorough answer so I can understand models and relationships fully. And yes, I have read the docs.
Firstly, the thing to remember is that these classes are representations of underlying database tables. A ForeignKey field in a Django model represents a one-to-many relationship in the database, with an _id field representing the ID of another table. Those tables are themselves independent, but are linked via the FK field (and the relevant index constraint, if the database supports them).
That said, in your Car model manufacturer is a required field (because you haven't defined it as null=True). So when you create a Car, you must point it at an already existing Manufacturer - and that manufacturer must have been saved already, so that Django can populate the underlying manufacturer_id field with the ID of the related object
Because Django is aware of the foreign key relationship between the two objects, you can use them when querying. In SQL this would be done via JOINs: Django gives you a special syntax to do queries across those joins, via double underscores. So, for example, if you wanted to get all the cars made by a manufacturer created in 1990 (assuming that's what you mean by the company_created field), you would do this:
Car.objects.filter(manufacturer__company_created='1990')
Django translates this into something like":
SELECT * from car JOIN manufacturer ON car.manufacturer_id=manufacturer.id WHERE manufacturer.company_created='1990';
If you already have your "civic" instance and just want to get access to the related data, this is pure Python object access: civic.manufacturer is the related Manufacturer object, so you can simply do civic.manufacturer.company_created to get the relevant data. Again, Django translates that into the database access, but from your point of view this is simple object composition.
Note that really all this is fully explained in the tutorial, with relationships between Poll and Choice which exactly match your Manufacturer and Car models.
Yes manufacturer need to exist as an instance already.
you can create car instance like this:
manuf= Manufacturer(name='honda',company_created='Benz')
manuf.save()
civic = Car(manufacturer=manuf)
you can get the company_created data from the civic instance by:
civic.manufacturer.company_created
I've got a Django view that I'm trying to optimise. It shows a list of parent objects on a page, along with their children. The child model has the foreign key back to the parent, so select_related doesn't seem to apply.
class Parent(models.Model):
name = models.CharField(max_length=31)
class Child(models.Model):
name = models.CharField(max_length=31)
parent = models.ForeignKey(Parent)
A naive implementation uses n+1 queries, where n is the number of parent objects, ie. one query to fetch the parent list, then one query to fetch the children of each parent.
I've written a view that does the job in two queries - one to fetch the parent objects, another to fetch the related children, then some Python (that I'm far too embarrassed to post here) to put it all back together again.
Once I found myself importing the standard library's collections module I realised that I was probably doing it wrong. There is probably a much easier way, but I lack the Django experience to find it. Any pointers would be much appreciated!
Add a related_name to the foreign key, then use the prefetch_related method which added to Django 1.4:
Returns a QuerySet that will automatically retrieve, in a single
batch, related objects for each of the specified lookups.
This has a similar purpose to select_related, in that both are
designed to stop the deluge of database queries that is caused by
accessing related objects, but the strategy is quite different:
select_related works by creating a SQL join and including the fields
of the related object in the SELECT statement. For this reason,
select_related gets the related objects in the same database query.
However, to avoid the much larger result set that would result from
joining across a 'many' relationship, select_related is limited to
single-valued relationships - foreign key and one-to-one.
prefetch_related, on the other hand, does a separate lookup for each
relationship, and does the 'joining' in Python. This allows it to
prefetch many-to-many and many-to-one objects, which cannot be done
using select_related, in addition to the foreign key and one-to-one
relationships that are supported by select_related. It also supports
prefetching of GenericRelation and GenericForeignKey.
class Parent(models.Model):
name = models.CharField(max_length=31)
class Child(models.Model):
name = models.CharField(max_length=31)
parent = models.ForeignKey(Parent, related_name='children')
>>> Parent.objects.all().prefetch_related('children')
All the relevant children will be fetched in a single query, and used
to make QuerySets that have a pre-filled cache of the relevant
results. These QuerySets are then used in the self.children.all()
calls.
Note 1 that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously
cached results, and retrieve data using a fresh database query.
Note 2 that if you use iterator() to run the query, prefetch_related() calls will be ignored since these two
optimizations do not make sense together.
If you ever need to work with more than 2 levels at once, you can consider a different approach to storing trees in db using MPTT
In a nutshell, it adds data to your model which are updated during updates and allow a much more efficient retrieval.
Actually, select_related is what you are looking for. select_related creates a JOIN so that all the data that you need is fetched in one statement. prefetch_related runs all the queries at once then caches them.
The trick here is to "join in" only what you absolutely need to in order to reduce the performance penalty of the join. "What you absolutely need to" is the long way of saying that you should pre-select only the fields that you will read later in your view or template. There is good documentation here: https://docs.djangoproject.com/en/1.4/ref/models/querysets/#select-related
This is a snippet from one of my models where I faced a similar problem:
return QuantitativeResult.objects.select_related(
'enrollment__subscription__configuration__analyte',
'enrollment__subscription__unit',
'enrollment__subscription__configuration__analyte__unit',
'enrollment__subscription__lab',
'enrollment__subscription__instrument_model'
'enrollment__subscription__instrument',
'enrollment__subscription__configuration__method',
'enrollment__subscription__configuration__reagent',
'enrollment__subscription__configuration__reagent__manufacturer',
'enrollment__subscription__instrument_model__instrument__manufacturer'
).filter(<snip, snip - stuff edited out>)
In this pathological case, I went down from 700+ queries to just one. The django debug toolbar is your friend when it comes to this sort of issue.
I'm developing kind of a social network in Django, but I don't see the way to maintain coupled my models.
I have a model User, which can comment on other Users, Pics, Pages (capitals are because they're models) via a Comment model. In order to arrange all that comments I created the Board model, that has one owner and receives all the comments addresed to that owner. The problem is I don't know how is its owner, i.e., which model does it belong to. It could be a pic's board, but also a user's one. So I end up with a model like this:
class Board(models.Model):
category = models.IntegerField()
owner_id = models.IntegerField()
I store owner's id and owner's category to be able to perform other tasks, but this solution doesn't convince me at all. A friend has advised me to use an abstract class Board, and then create a UserBoard, PicBoard, PageBoard which inherit from Board, but I think that will be useless too. I've thought about GenericRelations, but I'm not sure if that is the correct way to achieve what I'm trying. Any proposal will be listened and considered, thanks for your help :)
PS: Oh, and sorry if the title isn't very descriptive, but I couldn't figure out a better one. It's hard to explain this problem
Option 1
Create a class BoardOwner. Have all models which have a board inherit from that, and have the board have a foreignkey relationship with BoardOwner. You'll need to then scan over the various childlinks to figure out which one is the "real" child. This more fiddly, but localises all of the complexity in one class.
Option 2
Have a foreignkey from each class that has a board to the board. If you always have boards enter your system via a method on the owner (as opposed to a query on Board or elsewhere), you can have code in the owner which lets the Board know which foreign key reverse relationship to use. You'll probably want to factor that code into its own class.
Option 3
Use contenttypes: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
This wraps up this sort of thing.
I am trying to parse this Django code (without any familiarity with Django, I might add)
Question.objects.filter(children__marked=True)
I know the model contains a table called "forum_node" with one of the column named "marked". From what I understand, this statement fetches all the questions where any of its children (= answers) are accepted (or "marked"). How does this magic work?
To understand what happens you should take a closer look at Django's docs explaining the query options and the object-relational mapping.
children refers to a related model (there should be an according m2m or foreign key field named children on your question model, indicating the related model, e.g. node) and marked is a field on the related model.
The Node model probably contains something like:
question = models.ForeignKey(Question, related_name='children')
marked = models.BooleanField()
The statement:
Question.objects.filter(children__marked=True)
Is just doing a join on the two tables and returning Question models that have at least one Node model with marked=True.