Alternative to django concrete inheritance - python

I have a Django model class which encompass various types of model classes like:
Content > (Audio, Video, Image)
I want to perform queries on this parent model like Content.objects.filter() or Content.objects.recent(). How do i come about this? Presently i am using django's concrete model inheritance, which I suppose impose lot of overheard on the db performance by using joins for the parent classes. I cannot use abstract class because that would not permit me to perform queries on the parent class. Here are my models definitions:
class BaseContent(models.Model):
"""
Concrete base model to encompass all the local and social content.
We need a single queryset for all the content on the app.
"""
title = models.CharField(_('title'), max_length=255, default='')
description = models.TextField(_('description'), default='', blank=True)
publisher = models.ForeignKey(settings.AUTH_USER_MODEL)
allow_comments = models.BooleanField(default=False)
is_public = models.BooleanField(default=True)
created = AutoCreatedField(_('created'))
objects = BaseContentManager()
class Video(BaseContent):
ACTIVITY_ACTION = 'posted a video'
UPLOAD_TO = 'video_files/%Y/%m/%d'
PREVIEW_UPLOAD_TO = 'video_frames/%Y/%m/%d'
video_file = models.FileField(_('video file'), upload_to=UPLOAD_TO)
preview_frame = models.ImageField(
_('Preview image'), upload_to=PREVIEW_UPLOAD_TO, blank=True,
null=True)
category = models.ForeignKey(VideoCategory, blank=True, null=True)
num_plays = models.PositiveIntegerField(blank=True, default=0)
num_downloads = models.PositiveIntegerField(blank=True, default=0)
Thanks in advance.

I've had a similar scenario which i have solved using an external named Django Polymorphic, the library seemed to work seamlessly. A few major projects use Django Polymorphic including Django-shop.
Link:
https://github.com/chrisglass/django_polymorphic
Don't quote me on this but i've read a few sources in the past that have mentioned that django_polymorphic models does not have the same performance issues caused by the standard Django ORM concrete inheritance implementation.

Related

Django ManyToMany alternative pros and cons

I was developing a chat system with channels and have this models for a thread (some attributes removed for simplicity's sake):
class Thread(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
users = models.ManyToManyField('auth.User')
I realized it is also possible to implement it like this:
class Thread(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
class ThreadUsers(models.Model):
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
What are the advantages/disadvantages of using one over the other?
All what you do - is the same. For your last example with custom M2M through model you can add M2M declaration users in Thread:
class Thread(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
# M2M declaration, which use your ThreadUsers
users = models.ManyToManyField('auth.User', through='ThreadUsers' )
class ThreadUsers(models.Model):
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
Pros:
You create model self
you can change behavior your M2M connection manually.
You can add additional fields in M2M through connection.
You have full control of this model.
Cons:
problem with m2m connections in django admin.
too much additional code, you can get a hard-to-find errors.
some fields/widgets don't want to work with M2M.through.
all was happened is your problem, this is not tested. Auto-through relation is tested in box.
we have in our projects 50/50 M2M-autothrough vs M2M-manualthrough. if I want to have more control on the models and realations - i use custom through.
p.s. in M2M-autothrough case Django created SomethingLikeYourThreadUsers Model and Table automatically.

How to Connect a Django Model with ManyToMany Relationship?

I am making an app that is pretty much similar to google classroom in django.
I have a Course model and an assignment model, and I want to connect an assignment to the specified course.
These are my models
class Assignment(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
date_created = models.DateTimeField(default=timezone.now)
class Course(models.Model):
title = models.CharField(max_length=100)
subject = models.CharField(max_length=100)
image = models.ImageField(default='no_course_image.jpg', upload_to='course_images')
owner = models.ForeignKey(User, on_delete=models.CASCADE)
students_invited = models.ManyToManyField(User, null=True, blank=True)
assignments = models.ManyToManyField(Assignment, null=True, blank=True)
date_published = models.DateTimeField(default=timezone.now)
class Meta:
verbose_name_plural = 'Course'
ordering = ['-date_published']
def __str__(self):
return '{} - {}'.format(self.title, self.owner)
But i am getting an error when I specify the course field in the assignment model with the ForeignKey!
Could you please help me with how to connect the assignment to the Course model?
Thank you
ForeignKey is used to setup a many to one relationship. As you are trying to setup a ManyToManyField it won't work in this situation as you can see in the Django documentation
ForeignKey¶
class ForeignKey(to, on_delete, **options)¶
A many-to-one relationship. Requires two positional arguments:
the class to which the model is related and the on_delete option.
In fact you don't even need to set the relation in the Assignment Model as Django will take care of creating a third table linking the two together by their primary keys. You can see this in the documentation
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
So every time you add the assignment to the course like so
>>> c1 = Course(title='Python Course')
>>> c1.save()
>>> a1 = Assignment(name='Python Assignment')
>>> a1.save()
>>> c1.assignments.add(a1)
And the relation will automatically be created and c1.assignments.all() will return all the assignments linked to the course
If you need to go the other way around then you would use a1.course_set.add(c1). When using the model that doesn't have the ManyToManyField object tied to it you need to use the *_set notation where * will be replaced by the model name in lower case. Can read more about Related Objects references in the docs here
When you try to create the Model Assignment with reference to the model Course, the Course Model has not yet created and vice versa and you will get an error either of the model is not defined
You can use the quotes for it
class Assignment(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
date_created = models.DateTimeField(default=timezone.now)
You can use a custom through model enter link description here
I guess the Course model has to be written before the Assignment model.

manytomany field not working django-cms

I am using django-cms
many to many field is working fine when i add plugins or update but
after publish page i didn't get any data where i add many to many field.
models are look like this
#python_2_unicode_compatible
class ClientLogo(CMSPlugin):
client_logo = models.ManyToManyField(LogoPluginModel, blank=True)
class LogoPluginModel(CMSPlugin):
title = models.CharField(max_length=100)
here field 'client_logo' will be disapper when i publish djagno-cms page
The relations need to be explicitly copied through the copy_relations method (see django-cms models manual). It's also advantageous to add a related_name property to the ManyToManyField, especially when a model contains multiple sets of foreign keys or ManyToManyFields.
#python_2_unicode_compatible
class ClientLogo(CMSPlugin):
client_logo = models.ManyToManyField(
LogoPluginModel,
blank=True,
related_name='client_logos',
)
class LogoPluginModel(CMSPlugin):
title = models.CharField(max_length=100)
def copy_relations(self, oldinstance):
self.client_logos.all().delete()
for logo in oldinstance.client_logos.all():
logo.pk = None
logo.showroom = self
logo.save()

Django reference a Model by foreign key or a different field

I am using Django REST Framework. I have two models, Sites and Statuses.
class Sites(models.Model):
site_id = models.AutoField(primary_key=True)
status = models.ForeignKey(Statuses, models.DO_NOTHING, blank=True, null=True)
class Statuses(models.Model):
status_id = models.AutoField(primary_key=True)
description = models.CharField(max_length=255, blank=True, null=True, unique=True)
class Meta:
managed = True
db_table = 'Statuses'
I would like to be able to perform a GET on sites, and have the Statuses.description field returned (instead of Statuses.status_id). Also, I would like it so that either status_id or description may be used interchangeably in a POST to create a new site. Where does this type of functionality belong (serializer, models, etc...)?
I know I can accomplish the first part of my question by adding a property to the Sites model and then referencing this field in the Sites serializer.
#property
def status(self):
return self.row_status.description
However I thought the convention of a Model is that it should be a 1:1 representation of the database table. Is there a better way to do this?
This fits well in the serializer, like this:
class SitesSerializer(serializers.ModelSerializer):
description = serializers.CharField(source='status.description')
class Meta:
model = Sites
fields = ('site_id', 'description')
(But the status field should probably not have null=True set.)

Use a class before its definition in Django model

When I try to syncdb I get the error Menu is not a valid class Name.
How can I resolve that relationship case :
class MenuItem(model.Models)
title = models.CharField(max_length=200)
submenus = models.ManyToManyField(Menu, blank=True, null=True)
class Menu(Container):
links = models.ManyToManyField(MenuItem)
From the Django book:
If you need to create a relationship on a model that has not yet been
defined, you can use the name of the model, rather than the model
object itself:
E.g.:
class MenuItem(model.Models)
title = models.CharField(max_length=200)
submenus = models.ManyToManyField('Menu', blank=True, null=True)
^ ^
Edit:
As Francis mentions (and as is written in the documentation):
It doesn't matter which model has the ManyToManyField, but you should only put it in one of the models -- not both.
One of these models has a many to many, the other one uses Django's reverse relations (https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward)
So how I would set it up:
class Menu(Container):
links = models.ManyToManyField(MenuItem)
class MenuItem(model.Models)
title = models.CharField(max_length=200)
Then when I wanted a MenuItem's Menus:
menu_item_instance.menu_set.all()

Categories