Mixin inhheritance for models in django - django

Is there a way to build django models hierarchy like this?
class LikableObjectMixin(models.Model):
# mixin for all likable objects: posts, photos, etc
likers = models.ManyToManyField(Account)
class Meta:
abstract = True
def save():
super(LikableObjectMixin, self).save()
class Post(LikableObjectMixin, models.Model):
message = models.TextField(_('Post'))
author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='posts', blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
Can south work with this kind of inheritance? Is this an appropriate way to build model hierarchy?
Django=1.5.1

Yes, it's perfectly fine. South will create proper m2m relations for all your models that inherit from your mixin. You don't even have to write save method explicitly. So:
class LikableObjectMixin(models.Model):
likers = models.ManyToManyField(Account)
class Meta:
abstract = True
class Post(LikableObjectMixin):
message = models.TextField(_('Post'))

Related

How to add a field to model with a decorator?

I'd like to add foreign keys to virtually every model in my app to allow different Sites. For this I think it would be nice to use decorators, because I will be able to only add those FKs under certain conditions (e.g. if Sites is installed).
Unfortunately my attempt doesn't do anything:
def add_site_fk_field(model_to_annotate: models.Model):
"""Add FK to Site to Model"""
model_to_annotate.site = models.ForeignKey(Site, on_delete=models.CASCADE)
return model_to_annotate
#add_site_fk_field
class Test(models.Model):
...
Is it somehow possible to do this? I prefet not to use abstract classes.
As I know you cant do it with decorator. But you can do that with creating an abstract base model class.
For example:
from django.db import models
class Site(models.Model):
name = models.CharField(max_length=60)
class AddSiteFkField(models.Model):
fk_site = models.ForeignKey(Site, on_delete=models.CASCADE)
class Meta:
abstract = True
class Test(AddSiteFkField):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)

How to write test case for a Django model which has all the fields as foreignkey in DRF?

I have a model which has all the fields as a foreign key to other models. How can we create test case in Django rest framework in that case??
I have a model as follows:
class Example(models.Model):
package = models.ForeignKey(
Destination, related_name="packages", on_delete=models.CASCADE
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
null=True,
related_name="user_packages",
)
tour = models.ForeignKey(
Tours,
on_delete=models.CASCADE,
null=True,
related_name="tour_packages",
)
In a model, when there is just one field in a Django model, it can be done in the following way:
class NewsLetter(models.Model):
NewsLetterID = models.AutoField(primary_key=True)
Email = models.CharField(max_length=255)
Connected = models.BooleanField(default=False)
UserID = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = 'NewsLetter'
#classmethod
def setUpTestData(cls):
#Set up non-modified objects used by all test methods
user = User.objects.create(<fill params here>)
NewsLetter.objects.create(NewsLetterID=1, Email='test#test.com', Connected=False,UserID=user)
So even if I have created all the objects for all the foreign-key fields just like this example, the thing is, for the related field models, they themselves have foreign key fields. How can we approach this?? For example in my Example model, the Destination model is itself related to other foreign key fields. So how to create unit test for create api for this Example model??
I think you are approaching this correctly: You will have to setup all required test instances in the right order and link them appropriately.
To make this less cumbersome and more readable, you could use a project like factory_boy to generate fixture factories. Your setup could then look something like this:
import factory
# Define your factories
class PackageFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'yourapp.Package'
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'yourapp.User'
class TourFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'yourapp.Tour'
class ExampleFactory(factory.django.DjangoModelFactory):
package = factory.SubFactory(PackageFactory)
user = factory.SubFactory(UserFactory)
tour = factory.TourFactory(TourFactory)
class Meta:
model = 'yourapp.Example'
# And now, create a new example instance together with all related models.
example = ExampleFactory()
# Or create some of them separately and pass them into the factory.
package = PackageFactory()
example = ExampleFactory(package=package)

Common fields for different django models in one place

I have some columns that are repeated in multiple models. is there any solution to place them somewhere and use it any model?
You can achieve this by creating base classes and inheriting them in your models.
Example:
class TimestampsModel(models.Model):
#classmethod
def get_fields(cls, fields: tuple):
return fields.__add__(('created_at', 'updated_at'))
created_at = models.DateTimeField(("created_at"), auto_now_add=True)
updated_at = models.DateTimeField(("updated_at"), auto_now=True)
You can also make it abstract and Django won't create migrations for this.
class Meta:
abstract = True
Finally, a model would be:
class Blog(baseModels.TimestampsModel):
class Meta:
db_table = "blog"
title = models.CharField(max_length=100)

Proxy model for Multiple models in Django

I would like to display a model in the django admin but with the logic to choose between 2 models to display.
Current Implementation:
Models
class User(models.Model):
created = models.DateTimeField(auto_now_add=True, null=True)
last_updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=30, blank=True)
class ExpectedNames(User):
class Meta:
proxy=True`
Admin
#admin.register(ExpectedNames)
class ExpectedNamesAdmin(admin.ModelAdmin):
date_hierarchy = 'created'
What I Would like to DO: # something like this
Models
class User(models.Model):
created = models.DateTimeField(auto_now_add=True, null=True)
last_updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=30, blank=True)
class User2(models.Model):
created = models.DateTimeField(auto_now_add=True, null=True)
last_updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=30, blank=True)
class ExpectedNames(User):
class Meta:
proxy=True
if name == "Rick":
return User
else:
return User2
Admin
#admin.register(ExpectedNames)
class ExpectedNamesAdmin(admin.ModelAdmin):
date_hierarchy = 'created'
Any suggestions not sure if this is the correct way to do this.
I think this is not possible as it states in the Django Documentation:
Base class restrictions:
A proxy model must inherit from exactly one non-abstract model class. You can’t inherit from multiple non-abstract models as the proxy model doesn’t provide any connection between the rows in the different database tables. A proxy model can inherit from any number of abstract model classes, providing they do not define any model fields. A proxy model may also inherit from any number of proxy models that share a common non-abstract parent class.
https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models
I use magic method new in same situation.
I have model Documen with field document_type. If document_type is 'contract' i want ContractProxy, if 'offer' - OfferProxy.
For do this I create new proxy:
class RelatedDocumentProxy(Document):
class Meta:
proxy = True
def __new__(cls, *args, **kwargs):
doc_type = args[1]
if doc_type == 'contract':
return ContractProxy(*args, **kwargs)
return OfferProxy(*args, **kwargs)
document_type is first field and will first arg who pass to method

Does South handle model mixins?

I've created a mixin and inherited from it in some models. The problem is when I create a schema migration, the mixin's fields are there.
class MyMixin(object):
a_field = models.CharField(max_length=30, blank=True)
another_field = models.DateTimeField(blank=True, null=True)
class Meta:
abstract = True
class MyModel(models.Model, myMixin):
...
Any ideas?
Seem to have got it working using the following
class MyMixin(models.Model):
a_field = models.CharField(max_length=30, blank=True)
another_field = models.DateTimeField(blank=True, null=True)
class Meta:
abstract = True
class MyModel(myMixin, models.Model):
...
The changes are:
MyMixin inherits Model rather than object (despite many discussions around the place saying that mixins for django should inherit object rather than Model)
the order of inheritance for MyModel - the mixin has to come first