Can I change DB table name from the default automatically on Django? - python

I would like to change the DB table names on Django1.9. I know we can change the standard issue with "db_table".
Class Foo_Bar:
class Meta:
db_table = "foo_bar"
But I need to write that in every single class and it is tiresome.
I want Django creates a table whose name is lower-cased class name automatically.
But I have no idea how to do.
I even tried to use
self.__class__.name__.lower()
but, I didn't know how Meta works well.
Any advice is helpful.
Thank you.

A very hack-ish method but this code will give you the outer (since you want to get Foo_Bar, not Meta) class name:
import traceback
Class Foo_Bar:
...
class Meta:
db_table = traceback.extract_stack()[-2][2].lower()

Related

Django: how to change table names globally?

I know I can change table name per model using db_table attribute, as explained in the doc.
However, what if I want to do it globally? Let's say, I want all my table to be like:
db_table = f"table_{{model_name}}"
Is there any setting for this?
Otherwise, I guess I could use a mixin to be inherited from. However, the whole purpose of doing this is to NOT think of table naming when any developer will add a new model.
After reading this issue, It seems maintainers didn't even consider to add this feature as they did not understand the need, which is pretty clear to me :/
Any idea? Thanks.
The default database table naming goes like db_table = f"{app_label}_{model_name}" and you can rewrite them As hedde-van-der-heide suggested, by creating an abstract base model and subclassing them on your models, like
from django.db import models
class BaseModel(models.Model):
class Meta:
abstract = True
db_table = f"table_{model_name}"
class NewModel(BaseModel):
name = models.CharField(max_length=128)
def __str__(self):
return str(self.name)

generate django 2.0 model from a dict

Consider the following Django model:
class Person(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
I would like to define this class from a “static” dict (to be specific in my case it is generated from a file which will not change - so no need to makemigrations and migrate apart from first time).
Here is some pseudo-code to better explain what I want to achieve:
persondict = {‘first_name‘: models.CharField(max_length=255), ‘last_name’: models.CharField(max_length=255)}
class Person(models.Model):
#generate fields from persondict
This is just to start with. Note that you have to change the app_label inside the function, also this will work if you define it inside your models.py where you will use it, otherwise you will need to replace the '__module__' with the appropriate value.
def generate_person_model_from_a_dict(person_model_dict):
class Meta:
app_label = 'your_app_label_here'
person_model_dict.update({
'Meta': Meta,
'__module__': generate_person_model_from_a_dict.__module__,
})
Person = type("Person", (models.Model,), person_model_dict)
return Person
Meta.app_label is needed here to let the Django know which app the newly constructed model should be attached to, e.g. if you are creating it for the app blog and set the model's app_label to blog, then the Django will know, that the app has this model on it (just like you would define it in your blog/models.py)
__module__ is a special attribute of python objects (you can read details about it here https://docs.python.org/3/reference/datamodel.html ) To be brief, it lets Django to know which module your class belongs to, it uses it mostly to display various messages to it's user, see here: https://github.com/django/django/search?utf8=%E2%9C%93&q=module&type=
(just set it to your models.py like in the above example is therefore what Django pretty much expects)

How to create exact duplicate of Django model that has M2M and FK relationships

I have a Django model that already exists that I'd like to duplicate, and I can't figure out an easy way how because of related-name conflicts across ForeignKeys and ManyToManys.
As an example, let's call the model I currently have Dog:
class Dog(models.Model):
name = models.CharField()
owner = models.ForeignKey('myapp.Owner')
breeds = models.ManyToMany('myapp.Breed', help_text="Remember, animals can be mixed of multiple breeds.")
I'd like to make an exact duplicate of this model for use elsewhere, with a different database table and name. I tried using an abstract base class:
class AnimalAbstract(models.Model):
name = models.CharField()
owner = models.ForeignKey('myapp.Owner')
breeds = models.ManyToMany('myapp.Breed', help_text="Remember, animals can be mixed of multiple breeds.")
class Meta:
abstract = True
class Dog(AnimalAbstract):
pass
class Cat(AnimalAbstract):
pass
This fails because of related_name conflicts.
Is there any way to automatically copy a model like this without explicitly redefining every ForeignKey and ManyToMany?
To preemptively answer questions: yes, I know about multi-table inheritance, and I don't want to use it. I also know that I could simply store this all in the same table and use proxy models with custom managers to automatically filter out the wrong type of animal, but I don't want that either—I want them on separate database tables.
https://docs.djangoproject.com/en/1.8/topics/db/models/#abstract-related-name
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.
%(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.
Ex:
class Dog(models.Model):
name = models.CharField()
owner = models.ForeignKey(
'myapp.Owner',
related_name="%(app_label)s_%(class)s_dogs")
breeds = models.ManyToMany(
'myapp.Breed',
help_text="Remember, animals can be mixed of multiple breeds.",
related_name="%(app_label)s_%(class)s_dogs")

Bi-directional relationship in mongoengine

I need to use a bi-directional relationship in Mongoengine which is something like the below.
from mongoengine import *
class Notification(Document):
desc = StringField()
from_user = ReferenceField('User')
class User(Document):
Name = StringField()
notifications = ListField(EmbeddedDocumentField(Notification))
I know we can put single quoted class name there when the class has not yet defined.
from_user = ReferenceField('User')
However, we got a problem here. Seems like in runtime it interprets our class as mongoengine.django.auth.user instead of our custom user class. (This is just what I guess but in runtime during debug mode I find that it misinterprets it as mongoengine.django.auth.user although the record in the collections should belong to the custom user class)
So is there any way for me to specify a fully qualified class name there?
Thanks!
In this instance you'd need to declare the User class after the Notification class.
Internally mongoengine uses a class registry, which is populated via the Document metaclass. Unfortunately, namespacing isn't the same as in the java world (I never thought I'd say that!) so as far as I know its not possible to determine the full location name for a class eg: myapp.models.User
Are you using the django User class? as well as another User class - this will cause issues with the registry as currently you can only have one class per name.

Use of meta class in django

Can someone please explain why is meta class used in the following example.
Ex:
Class Employee (models.Model):
name = models.ForeignKey(name)
Gender = models.IntegerField()
class Meta:
ordering = ["Gender"]
Thanks.
Django models use the Meta class to contain extra information about the model that would not necessarily be appropriate to contain within the model class itself. Note that this is not the same as Python's metaclass; that is a completely different topic.
In this case it ordering or sorting the queries to this model by field "Gender"
Because author/programmer wants to sort results by value of Gender field.
In this case it defines the default field for ordering if you don't provide ORDER_BY in your query.
It is explained in Django Documentation for Models
https://docs.djangoproject.com/en/dev/topics/db/models/
Give your model metadata by using an inner class Meta, like:
Class Employee (models.Model):
....
class Meta:
ordering = ["attribute-X"]
Another useful option can be used in class Meta is verbose_name.

Categories