Prevent Django from joining superclass' table - django

Having a non-abstract parent class:
class Animal(models.Model)
and two subclasses:
class Cow(Animal)
class Dog(Animal)
and calling
Dog.objects.order_by('name')
queries the database and returns joined records:
SELECT ... FROM dog
INNER JOIN animal ON (dog.animal_ptr_id = animal.id)
ORDER BY dog.name ASC
However in my case "dog" is not a table, but a complicated view defined in the database. The view already contains all needed fields from "animal" including the animal id accessible by animal_ptr__id.
How can I prevent django from making the INNER JOIN which drastically slows down the query?

I don't really understand why you think dog is not a table in this case, since you are not using abstract base class. It is therefore multi-table inheritance and each subclass does have a table.
To the best of my knowledge the best way to avoid INNER JOIN for multi-table inheritance is to use abstract base class by setting abstract = True in class Meta. It seems like this what you should be doing, but..
It is possible, however, to use raw SQL queries if you insist on using multi-table inheritance. Something like this might work:
Dog.objects.raw('SELECT ... FROM myapp_dog ORDER BY dog.name ASC')
Though dog table alone will not contain the properties it inherited from the base class Animal. To get those inherited properties, I think a JOIN is unavoidable unless I missed something obvious..

However in my case "dog" is not a table, but a complicated view
defined in the database.
You need to set managed = False for Dog; otherwise you aren't using your view but an intermediary table called app_dog (where app is your app name).
This prevents django from creating a table but to use one internally defined (in your case, the view). Make sure you also specify a key, and specify the table name.

Related

Even with copy.deepcopy(django.model), _meta options are shared

I have several tables with exactly the same structure (columns) but different elements (rows). These tables are spatial grids and each table defines a zooming level, therefore it's not necessary to write a model for each one (at least that's what I thought). My approach was to change the attribute ._meta.db_table to the table I need to do my stuff.
The problem is that if I instantiate an object M, say for level 1 (i.e. M._meta.db_table == "table-level-1"), and then instantiate another object N, say for level 2 (i.e. N._meta.db_table == "table-level-2") that same attribute in object M will change as well. Even if I use a deep copy of it!
Do you have any idea how to fix this?
I'm not sure I understand exactly what you've done, but here's how I would implement multiple models with the same structure.
class MyBase(models.Model):
foo = models.Integer()
# and so on
class Meta:
abstract = True
class MySubOne(MyBase):
pass
class MySubTwo(MyBase):
pass
By setting abstract=True on the base model, Django won't create a table for that model. But it will create a table for each of the models that inherits from it. More info: https://docs.djangoproject.com/en/1.7/topics/db/models/#abstract-base-classes

Doctrine2: OneToMany on mapped superclass

My DB structure is as follows:
work:
CTI table Work
MappedSuperclass table AbstractImageWork which extends Work
final table PhotoWork which extends AbstractImageWork
comment:
MappedSuperclass table Comment
final table WorkComment which extends Comment
WorkComment has a ManyToOne relation to Work:
#ManyToOne(targetEntity="Work", inversedBy="comments")
Work has a OneToMany relation to WorkComment:
#OneToMany(targetEntity="WorkComment", mappedBy="work")
The problem is that Doctrine gives me this error while updating the schema:
[Doctrine\ORM\Mapping\MappingException]
It is illegal to put an inverse side one-to-many or many-to-many association on
mapped superclass 'Acme\...\AbstractImageWork#comments'.
I guess this has something to do with the MappedSuperclass AbstractImageWork stuck in the middle between Work and PhotoWork, but I didn't actually put this relation on the MappedSuperclass, but on the CTI table.. so why will Doctrine behave like this?
Any ideas?
In some cases, when you have such error when inherit from the class that is tagged as #ORM\MappedSuperclass, try to change your properties access level from private to protected
A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all. Furthermore Many-To-Many associations are only possible if the mapped superclass is only used in exactly one entity at the moment. For further support of inheritance, the single or joined table inheritance features have to be used.
Check it out here: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html
In others cases happens when you declare #ORM\Entity in an abstract superior class instead of #ORM\MappedSuperclass

Creating OneToOneField with base model

Sometimes in course of time model becomes too huge. There is a desire to split it on a several models and connect them with OneToOneField. Fields that uses most often, kept in primary model, other fields moves into other models.
However this approach becomes a headache when creating new instance of model. When you can initialize one model with one line:
MyModel.objects.create(foo=1, bar=2)
you needs at least two lines to initialize two models:
instance = MyModel.objects.create(foo=1, bar=2)
MyRelatedModel.objects.create(mymodel=instance, hello=3, world=4)
Is there a way to simply create two models in one line, or i should write my own auxiliary function for such problems?
I think, You should not split your models with onetooneField because of following reasons
As you said there will be some extra code to manage them.
Every time you query them you will have to make two queries instead of two.
Please don't forget that django models has two functions. The keep data related methods and they keep data model of your application. Some bussiness models have tables that have hundreds of fields. This is completely normal. If you really want to split them. you might want to check out abstract base classes. those are base classes for your model that does not have a seperate tables for themselves https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes
But if you insist on going with oneToOne field you can wrap object creation code in one of the model's method like
MyMode.create(attr_for_model_A=1, attr_for_model_B=2)
Or you can overwrite default manager's create method to create two method instead of one
https://docs.djangoproject.com/en/dev/topics/db/managers/#modifying-initial-manager-querysets
In my opinion, non-of those will worth having small model code.

Django model inheritance vs composition, and querying multiple models/tables together

I have a Django app that has a number of different models, all with a bunch of common data. Ultimately, I think this question comes down to a decision between inheritance and composition. My current implementation is something like this:
class Thing(models.Model):
foo = models.FooField()
bar = models.BarField()
type = models.CharField()
class A(CommonStuff):
aFoo = models.FooField()
class B(CommonStuff):
bFoo = models.FooField()
With this model, I'm able to query for a Thing using the Thing model's manager. Using the type field on Thing, I can get the child object data by looking at the type field, which contains either 'a' or 'b', and then asking for (i.e.) thing.a.aFoo. This is a feature I like because it's a fairly common operation in my app to get a list of all Thing objects.
I see a couple couple issues here. First, the type field seems unnecessary. Is there way to get at the child data without having to first look up the type? It seems like I could work around this with an instance method that returned the correct object given its type value, or if I really wanted to get rid of the type field, I could iterate over each of the reverse relation fields on Thing, looking for one that doesn't raise a DoesNotExist exception. This feels quite brittle to me though. If I add a new 'subthing' C, I have to update Thing to look for the new type. I could fix this by making Thing and abstract model. That way, A and B get all the fields of Thing and I avoid having to use the type field. Problem, though, is that I lose the ability to perform queries for all Thing objects.
Another model I'm thinking about sort of flips this one on its head by turning the data in Thing into a field on A and B.
class Thing(models.Model):
foo = models.FooField()
bar = models.BarField()
class A(models.Model):
aFoo = models.FooField()
thing = models.OneToOneField(Thing)
class B(models.Model):
bFoo = models.FooField()
thing = models.OneToOneField(Thing)
This version has a few benefits. It gets rid of the type field on Thing, and—at least to me—looks and feels cleaner and less brittle. The problem here, though, is the same as the problem with making Thing abstract in the first version. I lose the ability to query all my 'subthings' together. I can do a query for A objects or a query for B objects, but not both. Can use this version of the model without having to sacrifice the ability to query for all 'subthings'? One possibility is to write a manager that queries both models and returns a QuerySet of all the objects. Does that work?

Circular dependency in Django ForeignKey?

I have two models in Django:
A:
b = ForeignKey("B")
B:
a = ForeignKey(A)
I want these ForeignKeys to be non-NULL.
However, I cannot create the objects because they don't have a PrimaryKey until I save(). But I cannot save without having the other objects PrimaryKey.
How can I create an A and B object that refer to each other?
I don't want to permit NULL if possible.
If this is really a bootstrapping problem and not something that will reoccur during normal usage, you could just create a fixture that will prepopulate your database with some initial data. The fixture-handling code includes workarounds at the database layer to resolve the forward-reference issue.
If it's not a bootstrapping problem, and you're going to want to regularly create these circular relations among new objects, you should probably either reconsider your schema--one of the foreign keys is probably unnecessary.
It sounds like you're talking about a one-to-one relationship, in which case it is unnecessary to store the foreign key on both tables. In fact, Django provides nice helpers in the ORM to reference the corresponding object.
Using Django's OneToOneField:
class A(models.Model):
<snip>
class B(models.Model):
a = OneToOneField(A)
Then you can simply reference them like so:
a = A()
a.save()
b = B(a=a)
b.save()
print a.b
print b.a
In addition, you may look into django-annoying's AutoOneToOneField, which will auto-create the associated object on save if it doesn't exist on the instance.
If your problem is not a one-to-one relationship, you should clarify because there is almost certainly a better way to model the data than mutual foreign keys. Otherwise, there is not a way to avoid setting a required field on save.