I am having a model Player
with my django app .
class Player(models.Model):
""" player model """
name = models.CharField(max_length=100, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
hash = models.CharField(max_length=128, null=True, blank=True)
bookmark_url = models.CharField(max_length=300, null=True, blank=True)
As per my requirement i need to create a new model BookmarkPlayer
which will have all fields of Player
model.
Right now i have two things into my mind to do this .
class BookmarkPlayer(Player): """ just a bookmark player""" class Meta: app_label = "core"
class BookmarkPlayer(models.Model): """ bookmark player model """ name = models.CharField(max_length=100, null=True, blank=True) date_created = models.DateTimeField(auto_now_add=True) last_updated = models.DateTimeField(auto_now=True) hash = models.CharField(max_length=128, null=True, blank=True) bookmark_url = models.CharField(max_length=300, null=True, blank=True)
I just want to know which way is better to do this .Please share with my if there is another good way.
Updated Question
Knbb's idea to create a base class is interesting but i am facing issue with one of my model which is already existed into database.
My actual models :
class Address(models.Model): address = models.TextField(null=True, blank=True) class Site(models.Model): domain = models.CharField(max_length=200) class Player(models.Model): # ... other fields shipping_address = models.ForeignKey(Address, related_name='shipping') billing_address = models.ForeignKey(Address, related_name='billing') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now_add=True) site = models.ManyToManyField(Site, null=True, blank=True) class Meta: abstract = True
Models after changes :
class Address(models.Model): address = models.TextField(null=True, blank=True) class Site(models.Model): domain = models.CharField(max_length=200) class BasePlayer(models.Model): # .. other fields shipping_address = models.ForeignKey(Address, related_name='shipping') billing_address = models.ForeignKey(Address, related_name='billing') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now_add=True) site = models.ManyToManyField(Site, null=True, blank=True) class Meta: abstract = True class Player(BasePlayer): class Meta: app_label = 'core' class BookmarkPlayer(BasePlayer): class Meta: app_label = 'core'
After these changes when i am running my django server i am getting errors given below.
django.core.management.base.CommandError: One or more models did not validate: core.test1: Accessor for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. core.test1: Reverse query name for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. core.test1: Accessor for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'. core.test1: Reverse query name for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'. core.test2: Accessor for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. core.test2: Reverse query name for field 'shipping_address' clashes with related field 'Address.shipping'. Add a related_name argument to the definition for 'shipping_address'. core.test2: Accessor for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'. core.test2: Reverse query name for field 'billing_address' clashes with related field 'Address.billing'. Add a related_name argument to the definition for 'billing_address'
Answer :
Finally i got answer if we are using the related_name attribute on a ForeignKey or ManyToManyField into a Abstract model.
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) each time .
To work around this problem, when you are using related_name in an abstract base class (only), part of the name should contain '%(app_label)s' and '%(class)s'.
https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes
Now my BasePlayer model is
class BasePlayer(models.Model): # .. other fields shipping_address = models.ForeignKey(Address, related_name='%(app_label)s_%(class)s_shipping') billing_address = models.ForeignKey(Address, related_name='%(app_label)s_%(class)s_billing') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now_add=True) site = models.ManyToManyField(Site, null=True, blank=True) class Meta: abstract = True
To answer your question, with the new migration introduced in Django 1.7, in order to add a new field to a model you can simply add that field to your model and initialize migrations with ./manage.py makemigrations and then run ./manage.py migrate and the new field will be added to your DB.
A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you're storing. Generally, each model maps to a single database table. The basics: Each model is a Python class that subclasses django.db.models.Model .
If your BookmarkPlayer
needs the same data but in a different table, an abstract base model is the best way to go:
class BasePlayer(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
hash = models.CharField(max_length=128, null=True, blank=True)
bookmark_url = models.CharField(max_length=300, null=True, blank=True)
class Meta:
abstract = True
class Player(BasePlayer):
""" player model """
pass
class BookmarkPlayer(BasePlayer):
""" bookmark player model """
pass
This way, both Player
and BookmarkPlayer
inherit their fields from the BasePlayer
model, but because BasePlayer
is abstract, the models are completely decoupled.
Multi-table inheritance on the other hand would still save the fields in a single table, but add an extra table for the BookmarkPlayer
with an implicit OneToOneField
to the Player
table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With