I wonder - is it possible to inherit classes like this?
For exmple, i have 2 abstract classes:
class Book(models.Model):
name = models.TextField()
class Meta:
abstract = True
class Page(models.Model)
num = models.IntegerField()
book = models.ForeignKey('Book')
class Meta:
abstract = True
And so - I want to make inherited classes for these two, let them be BigBook and BigBookPage
But if i do so, python says to me, that my FK field can't have a relation with an abstract model. And i can't find a way to redefine FK in inherited models. So do i have to ONLY create foreign keys in the inherited models - not the parents?
And if i have same model methods, that use foreign keys, defined in the parent models... i have to move them to every child - so they could use their foreign keys?
It sounds like you want to mark Book as proxy=True. See proxy models. It will create a book model, but also let you have other models that inherit from it letting you customize the functionality of the subclasses.
class Book(models.Model):
class Meta:
proxy = True
class BigBook(Book):
# BigBook properties go here.
Related
I have this abstract model:
class HasSystemMessage(models.Model):
class Meta:
abstract = True
messages = models.ManyToManyField(SystemMessage, related_name=?)
I am going to use this abstract model in at least three other models, lets say, A, B, and C. How can I set the related_name dynamically for these classes? for example, for class B, I want the related_name to be Bs. Is it possible to do so?
To further clarify the question, The classes will look like this:
class B(HasSystemMessage):
# Some model fields
class A(HasSystemMessage):
# Some model fields
HasSystemMessage.objects.filter(a__contains=[some elements])
You can use %(class)s or %(app_label)s
class HasSystemMessage(models.Model):
class Meta:
abstract = True
messages = models.ManyToManyField(SystemMessage, related_name=%(app_label)s_%(class)s_related)
From Django docs
Be careful with related_name and related_query_nameĀ¶ If you are using
related_name or related_query_name on a ForeignKey or ManyToManyField,
you must always specify a unique reverse name and query name for the
field. This would normally cause a problem in abstract base classes,
since the fields on this class are included into each of the child
classes, with exactly the same values for the attributes (including
related_name and related_query_name) each time.
To work around this problem, when you are using related_name or
related_query_name in an abstract base class (only), part of the value
should contain '%(app_label)s' and '%(class)s'.
'%(class)s' is replaced by the lower-cased name of the child class
that the field is used in. '%(app_label)s' is replaced by the
lower-cased name of the app the child class is contained within. Each
installed application name must be unique and the model class names
within each app must also be unique, therefore the resulting name will
end up being different.
Ref: https://docs.djangoproject.com/en/2.0/topics/db/models/#be-careful-with-related-name-and-related-query-name
You Just need to put a string in this attribute which specifies the name of the reverse relation from the SystemMessage.Also read in Django Docs
Try this:
class HasSystemMessage(models.Model):
class Meta:
abstract = True
messages = models.ManyToManyField(SystemMessage, related_name='system_message')
I'm upgrading a project from django 1.8 to 1.10 and it looks like django has improved the check of eventual name collision between foreign keys and model inheritance.
This is obviously a good thing, but the projet I need to upgrade is a big one and it would be a hell to rename a model.
Let me explain the problem : I have a base class called Parent and many children which are linked together, like so :
class Parent(models.Model):
title = models.CharField(max_length=10)
class ChildA(Parent):
description = models.TextField()
class ChildB(Parent):
description = models.TextField()
childa = models.ForeignKey(ChildA)
The clash here is that a childb object has 2 "childa" attributes :
The "childa" ForeignKey
The instance inherited by the ChildA model (because childb has also the parent attributes).
The 2 obvious solutions here are :
Rename the ForeignKey ChildB.childa to ChildB.somethingelse
Rename the ChildA model to something else.
Both solutions costs a lot and will probably introduce new bugs.
So I wondered : Is it possible to rename the reverse related name of the inherited object ?
For example :
p = Parent.objects.get(pk=1)
print p.childa_child # Hit the ChildA instance
I have no idea if I'm clear enough but I'll keep this question up to date.
==== EDIT ====
To be more concise, if I have 2 models class Parent(models.Model) and class Child(Parent), a dynamic attribute parent.child is created.
Is it possible to edit this attribute name without touching the class name ?
Multi-table inheritance creates an implicit OneToOneField field between the base model and the subclass.
Django allows you to modify this relationship by explicitly setting the one to one field.
class Parent(models.Model):
title = models.CharField(max_length=10)
class ChildA(Parent):
parent = models.OneToOneField(to=Parent, parent_link=True)
description = models.TextField()
class ChildB(Parent):
parent = models.OneToOneField(to=Parent, parent_link=True)
description = models.TextField()
childa = models.ForeignKey(ChildA)
The important bit here is the parent_link=True argument which tells Django to use this field declaration for managing the multi-table inheritance with these two models.
So you can now set related_name='+' to prevent Django from creating a reverse relationship or you can set related_name to a more unique name:
class ChildA(Parent):
parent = models.OneToOneField(to=Parent, parent_link=True, related_name='child_a_here')
description = models.TextField()
class ChildB(Parent):
parent = models.OneToOneField(to=Parent, parent_link=True, related_name='child_b_here')
description = models.TextField()
childa = models.ForeignKey(ChildA)
I'm a little confused as to how ChildB has to two ChildA links, it looks like you left out some relationship fields from the models perhaps? Regardless, what I think you are looking for is the related_name parameter.
So with:
class ChildB(Parent):
description = models.TextField()
childa = models.ForeignKey(ChildA, related_name='b_children')
You could do a query like so:
a = ChildA.objects.get(id=1)
print(a.b_children)
You may also be interested in abstract models.
I would like to add the methods of the 'tools' class for 2 of my django model calss.
Each class will use the same methods with it's own model eample:
class mapA(models.Model):
mInd = models.IntegerField()
scId = models.IntegerField()
class mapB(models.Model):
mInd = models.IntegerField()
scId2 = models.IntegerField()
I would like to add the methods like checkInput() to both of them.
So I could run:
mapBInstance.checkInput();
mapAInstance.checkInput();
Ech time the checkInput runs over the data in the mapA or mapB.
I thought about creating a tools class & let each model to inherit from it.
This way the tools class will have logic which is identical to both maps.
When I read the django docs I didn't see example to this case only close solutions.
Is this the correct solution (to use the proxy class)?
class Tools():
def __init__():
...init class...
def checkInput():
..make the checks..
class MapA(Tools, models.Model):
mInd = models.IntegerField()
scId = models.IntegerField()
def checkSelf():
self.checkInput(self.objects.filter(....))
class MapB(Tools, models.Model):
mIndB = models.IntegerField()
scIdB = models.IntegerField()
def checkSelf():
self.checkInput(self.objects.filter(....))
A few things...
There is no this in Python, it's called self.
If you're in Python 2.x, tools should inherit from object. In Python 3, it's implicit, but doesn't hurt:
class tools(object):
...
If you're overriding __init__ in your mixin class (tools), then map classes should probably inherit from it first:
class mapA(tools, models.Model):
...
Only override __init__ if you really need to, it can get complicated.
Class names are pretty much always in CamelCase. This is not required, but is a convention. Also, It's a good idea to name mixin classes transparently:
class ToolsMixin(object):
...
class MapA(ToolsMixin, models.Model):
...
Other then all that, you perfectly can add a method in a mixin and use it in your models. No need for Django proxy models.
If you want MapA and MapB (it would be really helpful if you followed PEP-8) to be distinct models, proxy models won't help you. A proxy model is a model that is different in Python, but in the database it is exactly the same as the model it inherits from. Creating a proxy model that doesn't directly inherit from a single concrete model (one that has a table in the database) is an error.
What you're looking for is an abstract base class:
class Tools(models.Model):
...
class Meta:
abstract = True
class MapA(Tools):
...
class MapB(Tools):
...
An abstract model does not create its own table in the database. Instead, it is as if everything defined in Tools has been defined in both MapA and MapB, but the Tools class is otherwise ignored. This allows you to specify all the methods and fields just once, but still have two separate tables in the database.
I want to accomplish the following:
I have three classes derived from an abstract class:
class Person(models.Model):
name = models.CharField()
...
class Meta:
abstract = True
class TypA(Person):
...
class TypB(Person):
...
class TypC(Person):
...
In another class I would like to reference TypA and TypB as a Foreign Key, something like this:
class Project(models.Model):
worker = models.ForeignKey(TypA or TypB)
Since it is not possible to declare two different models as a Foreign Key I am on the look for solutions.
I read about Generic Foreign Keys; but I am unsure how to apply that to my model.
Another idea is to use the limit_choices_to declaration for ForeignKeys.
worker = models.ForeignKey(Person, limit_choices_to={??})
But this is not possible as it seems:
Field defines a relation with model 'Person', which is either not installed, or is abstract.
Thank you in advance for the help.
A Django ForeignKey field translates to a database foreign key. Your Person model is abstract, so that one doesn't exist in the database, so there can be no foreign keys to that one.
Likewise a database foreign key can only reference one table, not two.
If you really want a flexible relation to more than one kind of table, the only possibility I see is Django's contenttypes framework.
You also want to limit the kinds of models you can point at. For that you'd best look at How can I restrict Django's GenericForeignKey to a list of models? for an example.
you just need to reference your abstract class(like JAVA):
class Project(models.Model):
worker = models.ForeignKey(Person)
#in your code:
worker = TypeA()
worker.save()
proj = Project()
proj.worker = worker
proj.save()
class ItemForm(djangoforms.ModelForm):
class Meta:
model = Item
exclude = ['added_by']
i can not understand what this piece of code is doing .i understood that ItemForm is inheriting Modelform but then a class definition inside a class ??
The Item class is :
class Item(db.Model):
name = db.StringProperty()
quantity = db.IntegerProperty(default=1)
target_price = db.FloatProperty()
priority = db.StringProperty(default='Medium',choices=[
'High', 'Medium', 'Low'])
entry_time = db.DateTimeProperty(auto_now_add=True)
added_by = db.UserProperty()
It's part of Django's magic. The metaclass for ModelForm (among other classes) looks for an inner Meta class and uses it to make various changes to the outer class. It's one of the deeper parts of Python that most people will never have to deal with first-hand.
In Python you can define classes within other classes as a way of encapsulating the inner class. The way Django is using this is actually quite excellent.
See this link for more info: http://www.geekinterview.com/question_details/64739
Meta is a special class definition.
In this example, it is a simple inheritance model. ModelForm creates a form based on a Model class, so via giving a class definiton to ModelForm class, it creates the form elements according to related Model class definiton.