Django model inheritance: override restrictions in child classes - python

I will try to abstract my problem:
I need to create two model classes for IPv4 and IPv6.
I want to do it via inheritance; namely, to create a model class, and then to inherit from this class, but with the additional (different) limit for each of the child classes:
class IP(models.Model):
ip = models.GenericIPAddressField()
class Meta:
abstract = True
class IPv4(IP):
ip = models.GenericIPAddressField(protocol='ipv4')
class IPv6(IP):
ip = models.GenericIPAddressField(protocol='ipv6')
I'm not sure whether or not this is the correct way to do that, and I would like to know which problems might be caused due to such a model.

The Abstract Model is usually used to define a model with common fields.
If you define the same field in two models, that field is unnecessary for the base model.
However, in your code, that field('IP.ip') will be virtually absent, so it will not be an operational problem.

Related

ForeignKey between Django Models abstract base classes

I have a Django app where I want to use a set of abstract base classes to define certain models. I want to connect some of these abstract models through foreign keys.
I know that Django does not allow models.ForeignKey to abstract models. I've done some searching on StackOverflow and the general consensus solution seems to be - using GenericForeignKey. However, from my understanding, this results in an extra db-level SELECT call. I want to avoid this because quite a few of my abstract models have this kind of relationship. An example is given below:
class Person (models.Model):
name = models.CharField (max_length=256)
class Meta:
abstract = True
class Phone (models.Model):
phone_no = models.BigIntegerField ()
owner = models.ForeignKey (Person) # This is, of course, wrong. I'd like something like this.
class Meta:
abstract = True
Besides the posts about GenericForeignKey, I also came across a post about dynamic model generation. The link is given below. The question-poster themselves have provided the answer.
Defining an Abstract model with a ForeignKey to another Abstract model
I would like to ask:
if this still holds for the current versions of Django,
if there are any caveats I should be aware of, and
if there is perhaps a more contemporary solution?
Thank you.
I have solved the issue. As pointed by Willem and Mohit, I was thinking about the problem wrongly (I come from the Cpp world and am very new to the Python/Django programming mindset).
I ended up having the abstract classes defined without any relationships and then having concrete classes derived from these abstract ones actually define the relationships. This is also in keeping with the DRY principle.

Django - Pythonic way of extending parent and only changing child class fieldnames?

I'm working on some networking-related model mixins and I have two particular models that are supposed to be identical in every way except for their fieldname prefixes.
Picture:
class SrcEvent(models.Model):
src_ip = models.GenericIPField...
(...many more properties and methods...)
class DstEvent(models.Model):
dst_ip = models.GenericIPField...
(...many more properties and methods...)
Repeating everything twice (or even just extending one to get the methods on the other) doesn't sit well with me; what I'd like to end up with is a generic abstract class Event that just contains attributes like ip, hostname and such, then extend that with two child classes (SrcEvent and DstEvent) that append either "src_" or "dst_" to each field when the model is generated/migrated.
I can't just make Event and call it a day; some models mix in one, the other, or both sets of attributes, and the direction matters. These models are mixins. The models they get mixed into can have attributes pertaining to a source event (such as an alert), a destination event (such as an email), or both a source and destination event (netflow). So for example a Netflow(SrcMixin, DstMixin) model will have both the src_* and the dst_* sets of fields, which doesn't work if both mixins call their respective IP address field ip. This is why I need to maintain the distinction.
I do not know how to go about this within Django, or what to call it to look it up myself. Any tips would be appreciated!
I'm not sure about the 'mixin' aspects of this, but it sounds like a case for using an Abstract Base Class. with Source(Event) and Destination(Event) classes underneath it.
To define an abstract base class you would use something like:
class Event(models.Model):
class Meta:
abstract = True
#define all your common fields here
In the ORM, Source and Destination would become separate tables. As I said, I'm not sure about the 'mixin' aspects, but to a first approximation I think making Source and Destination abstract as well might work, so that objects which instantiate Source or Destination need all the fields populated?
I'm working around this through the use of formsets. I leave the fields generic, but I added a new CharField to indicate direction ('src' or 'dst'). Then I create the objects and references to events based on the number of forms submitted and their direction.

Django: How can I implement Hierarchy of classes in Django?

I am completely aware of MVC Framework and how Django implements models and views. What I want to know how can I implement custom Hierarchy classes and then use them in Django. For instance:
There is an abstract Class Employee and then subclasses; Permanent Employee,Interns etc. An employee can be hired and fired by the company.
Model inheritance in Django works almost identically to the way normal class inheritance works in Python, but the basics at the beginning of the page should still be followed. That means the base class should subclass django.db.models.Model.
The only decision you have to make is whether you want the parent models to be models in their own right (with their own database tables), or if the parents are just holders of common information that will only be visible through the child models.
There are three styles of inheritance that are possible in Django.
1)
Often, you will just want to use the parent class to hold information that you don’t want to have to type out for each child model. This class isn’t going to ever be used in isolation, so Abstract base classes are what you’re after.
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
Edit:
Abstract base classes
Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class. This model will then not be used to create any database table. Instead, when it is used as a base class for other models, its fields will be added to those of the child class. It is an error to have fields in the abstract base class with the same name as those in the child (and Django will raise an exception).
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
The Student model will have three fields: name, age and home_group. The CommonInfo model cannot be used as a normal Django model, since it is an abstract base class. It does not generate a database table or have a manager, and cannot be instantiated or saved directly.
For many uses, this type of model inheritance will be exactly what you want. It provides a way to factor out common information at the Python level, while still only creating one database table per child model at the database level.
2)
If you’re subclassing an existing model (perhaps something from another application entirely) and want each model to have its own database table, Multi-table inheritance is the way to go.
from django.db import models
class CommonInfo(models.Model):
# ...
class Meta:
abstract = True
ordering = ['name']
class Student(CommonInfo):
# ...
class Meta(CommonInfo.Meta):
db_table = 'student_info'
3)
Finally, if you only want to modify the Python-level behavior of a model, without changing the models fields in any way, you can use Proxy models.
from django.db import models
class Base(models.Model):
m2m = models.ManyToManyField(
OtherModel,
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)ss",
)
class Meta:
abstract = True
class ChildA(Base):
pass
class ChildB(Base):
pass
Along with another app rare/models.py:
from common.models import Base
class ChildB(Base):
pass
For more information you may want to continue reading the documentation here.
There is a well maintenanced project, called django-mptt, that implementing Modified Preorder Tree Traversal with your Django Models and working with trees of Model instances.
If i understand you right, you have two class hierarchies. You can use Bridge pattern to deal with it. Your custom hierarchy can be thought of as the abstraction and Django part as the implementation. The bridge pattern can also be thought of as two layers of abstraction.
The bridge pattern is a design pattern used in software engineering
that is meant to "decouple an abstraction from its implementation so
that the two can vary independently", introduced by the Gang of Four
(GoF). The bridge uses encapsulation, aggregation, and can use
inheritance to separate responsibilities into different classes.
https://en.wikipedia.org/wiki/Bridge_pattern

How to share and specialize base models in different Django applications?

We are developing a collection management project using Django, usable for different types of collections.
This problem quite naturally divides itself in two:
The common part, that will be shared by all collections.
The specializations, different for each collection type.
Example
To illustrate this a bit further, let's take a simplified example in pseudocode.
Common part
class ItemBase: # ideally abstract
name = CharField()
class Rental
item = ForeignKey("Item")
rented_to_person = CharField()
Specialization for a collection of cars
class ItemSpecialization
horse_power = Int()
 The problem
The question is how we could organize the code in order to allow reuse of the common part without duplicating its content ?
We would imagine it would be best to have the common part as a non-installed application, and have each specialized configuration as a separate installed application. But this would cause a problem with the Rental concrete class, because it resides in the common-part application.
Any advices on how we could proceed ?
It really depends on what you want, you may use an abstract model class for common stuff, and inherit from that in specialized model classes.
Otherwise, if you really want one table for all common data, typically to be able to relate to it, then you'll need your specialized model to have a relation to the common model. It can be a foreign key, or you can use model inheritance, in which case the foreign key in question will be managed for you by django, but it'll be harder to use.
It sounds like you're looking for a OneToOneField field relationship. Based on your example:
class ItemBase:
name = models.CharField(max_length=50)
class Rental:
item = models.OneToOneField(ItemBase)
rented_to_person = models.CharField(max_length=50)
class ItemSpecialization
item = models.OneToOneField(ItemBase)
horse_power = models.IntegerField()
With this model hierarchy, you could fetch Rental or ItemSpecialzation objects and also gain access to ItemBase fields. It's basically OO inheritance for Django models. More details in the docs: https://docs.djangoproject.com/en/1.9/topics/db/examples/one_to_one/

Django - get instances of base model as corresponding proxy models

I have a base Django model, and proxy models that subclass it. They override all methods. I need to iterate over all the instances of the base model (i.e. for i in BaseModel.objects.all()), but be able to call the methods of their corresponding proxy classes instead of the placeholder methods declared in the base class.
How do I approach this? I actually have a model field which can determine which proxy model corresponds to each particular instance. Maybe I can make use of it and cast the base class into the subclass somehow? I'm at a loss.
EDIT: I've had a look at this question and have managed to change the class by writing to self.__class__. However, is that safe to use with Django?
proxymodels = {"Foo": FooModel, "Bar": BarModel}
for o in BaseModel.objects.all():
proxymodels[o.type].method_name(o, *args, **kwargs)
The methods are called on the proxy models (the classes), passing the BaseModel instances as first argument plus any additional arguments you want to pass. That way the methods are called as if they were called on an instance of a proxy model.
PS: re-assigning self.__class__ seems very hackish to me.

Categories