I'm having a problem when using multi-table inheritance in Django and I didn't find something that solved it.
I have these two models:
class Person(models.Model):
id = models.CharField(primary_key=True, max_length=12, default="")
name = models.CharField(max_length=12, default="")
birthday = models.DateField()
class Parent(Person):
work = models.CharField(max_length=70, default="")
spouce_field = models.OneToOneField(Person, on_delete=DO_NOTHING, related_name="spouce_field")
And I get this error when running python3 manage.py makemigrations:
ERRORS:
family.Parent.spouce_field: (models.E006) The field 'spouce_field' clashes with the field 'spouce_field' from model 'person.person'.
Any idea what am I doing wrong?
I believe mrcai have answered your question here:
Mark your class Person as an abstract class to avoid field clashing.
You can specify Profile is an abstract class. This will stop the check
from being confused with your parent fields.
class Meta:
abstract = True
Related
What I'm trying to achieve is, having model Person that is created and managed by Django have a ManyToMany field with model Property that was "created" using inspectdb and already exists in the database.
(Property contains Geographical data and cannot be managed or changed by Django)
When trying to migrate, it raises :
ValueError: Related model 'cadastroapp.Property' cannot be resolved
Full stack here
Worth nothing that I removed from the migration file the step to create model Property, since it already exists and AFAIK there's no way to tell Django this in the model Class
models.py (simplified) :
class Person(models.Model):
objectid = models.AutoField(primary_key=True)
properties = models.ManyToManyField(
'Property',
through = 'Person_Property',
)
class Meta:
db_table = 'django_person'
class Person_Property(models.Model):
cod_person = models.ForeignKey('Person', on_delete=models.CASCADE)
cod_property = models.ForeignKey('Property', on_delete=models.CASCADE)
class Meta:
db_table = 'django_person_property'
class Property(models.Model):
objectid = models.BigIntegerField(unique=True, primary_key=True)
created_user = models.CharField(max_length=765, blank=True, null=True)
created_date = models.DateTimeField(blank=True, null=True)
last_edited_user = models.CharField(max_length=765, blank=True, null=True)
last_edited_date = models.DateTimeField(blank=True, null=True)
shape = models.TextField(blank=True, null=True) # This field type is a guess. - ESRI Shape
class Meta:
managed = False
db_table = '"GEO"."PROPERTY"'
There are a couple errors in your models.py file.
When defining a Foreignkey or ManytoMany field, you don't want the model name to be in quotes.
Please change:
class Person(models.Model):
properties = models.ManyToManyField(
'Property',
through = 'Person_Property',
)
and
class Person_Property(models.Model):
cod_person = models.ForeignKey('Person', on_delete=models.CASCADE)
cod_property = models.ForeignKey('Property', on_delete=models.CASCADE)
to:
class Person(models.Model):
properties = models.ManyToManyField(
Property,
through = 'Person_Property',
)
and
class Person_Property(models.Model):
cod_person = models.ForeignKey(Person, on_delete=models.CASCADE)
cod_property = models.ForeignKey(Property, on_delete=models.CASCADE)
then delete your migration file cadastroapp.0006_auto_20161122_1533.
then run makemigrations and migrate again.
This may still not migrate without errors, but it will get us on the right track.
I think that you want to put the model name in quotes. In case you leave it without quotes you have to ensure that the model is defined before the ManyToMany field has been defined. So you will need to have first class Property and then class Person in your file. When you put model name as "Property" then you do not need to care about order of class definitions.
I'm facing a problem with django-admin. I have three objects:
Description
Job
Project
And I want to edit the Description directly inside Job and Project.
Here is my model.py:
class Description(models.Model):
short_desc = models.TextField()
long_desc = models.TextField()
class Job(models.Model):
location = models.TextField()
desc = models.ForeignKey(Description)
class Project(models.Model):
name = models.TextField()
desc = models.ForeignKey(Description)
So, conceptually, Description is the parent of Job and Project.
And my admin.py:
class DescriptionInLine(admin.StackedInline):
model = Description
#admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
model = Project
inlines = [DescriptionInLine]
#admin.register(Job)
class JobAdmin(admin.ModelAdmin):
model = Job
inlines = [DescriptionInLine]
Whenever I run the django server, I get the following error:
<class 'admin.DescriptionInLine'>: (admin.E202) 'Description' has no ForeignKey to 'Job'.
I understand why I get the error: django expects the relation to be in the other way.
I also tried replacing ForeignKey by OneToOneField, without any success.
Any idea on how to solve this?
You get this error because inlines are intended to be used in the other direction (See this question).
I think for your usecase you'd better use model inheritance:
class Description(models.Model)
class Meta:
abstract = True
# Abstract is optional but I think for your usecase,
# standalone `Description` does not make any sense.
# If not `abstract`, a one-to-one relation will be implied
# between parent and children
short_desc = models.TextField()
long_desc = models.TextField()
class Job(Description):
location = models.TextField()
class Project(Description):
name = models.TextField()
I have an abstract base class that declares two foreign key fields to the user model:
class BaseModel(models.Model):
updated = models.DateTimeField(null=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="updated_by")
created = models.DateTimeField(null=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="created_by")
class Meta:
abstract=True
I have multiple classes that inherit from this class. When I run makemigrations, I get the following error for each possible class-pair and for both created_by and updated_by:
myapp.ClassA.updated_by: (fields.E305) Reverse query name for 'ClassB.updated_by' clashes with reverse query name for 'ClassB.updated_by'.
HINT: Add or change a related_name argument to the definition for 'ClassA.updated_by' or 'ClassB.updated_by'.
Even though I already have a related_name set. It works fine with just one of the two foreign key fields declared.
Is it possible to have two foreign key fields to the same model in an abstract class, and if so, how do I set it up?
This is the expected behavior as mentioned in the documentation.
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 BaseModel(models.Model):
updated = models.DateTimeField(null=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="updated%(app_label)s_%(class)s_related")
created = models.DateTimeField(null=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, related_name="created%(app_label)s_%(class)s_related")
class Meta:
abstract=True
Since you use the related_name more than once, in model classes you inherit, then related name for the user model is not clear and clashes.
You will have to set a different related_name for each model.
I used inheritance model in my project after changing the model; but I give non-nullable field error. What should I do?
I am using Django 1.7
class Questions(models.Model):
question_category = models.ForeignKey(Course, blank=False)
question_author = models.ForeignKey(Author, blank=False)
question_details = models.CharField(max_length=100, blank=False, default='')
timestamp = models.DateTimeField(auto_now_add=True)
class TypeFive(Questions):
question_title = models.CharField(max_length=100, blank=False, default=generator(5), unique=True, editable=False)
def __str__(self):
return "{}".format(self.question_title)
class TypeFiveChoice(models.Model):
question_choice = models.ForeignKey(TypeFive)
is_it_question = models.BooleanField(default=False)
word = models.CharField(default='', blank=False, max_length=20)
translate = models.CharField(default='', blank=False, max_length=20)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return "{} : {}, {}".format(self.question_choice, self.word, self.translate)
After migrations:
You are trying to add a non-nullable field 'questions_ptr' to typefive without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
In order to inherit from Questions in TypeFive, Django needs to add a relation from TypeFive to Questions. For all records in TypeFive that might already be in the database.
Django now doesn't know which question it should relate TopFive to. This is what the migrate command asks you for. You have a few options, but they greatly depend on your use case and whether you are in early development or if there is a production database where this migration has to run later.
I'm in early development and running it on localhost, so iI don't care
about my records. Now, what should I do?
In this case you haven't much to worry about, when migrate asks you type 1 and then press enter. Now add a primary key of a Questions instance that is in your database and then hit enter again.
Django now relates all TypeFive instances that are currently in the database to this question, so you might have to clean that up afterwards (e.g. by editing the TypeFive in Django admin).
#Nick Brady pointed this out in the question above so I don't mean to take credit but I wanted to highlight.
If your new inheritance class is only used for the purpose of being inherited from, you can easily get around this by setting your parent class to abstract.
class Parent(models.model):
Name = models.CharField(max_length=50)
class Meta:
abstract = True
class Child(Parent):
foobar = models.CharField(max_length=50)
class Meta:
db_table = "typenex_taxonomy_nodes"
I have a problem. I'm using Django 1.7, and have already made a custom user model, that inherits Django's abstract user like this:
class CustomUser(AbstractUser, BaseModel):
Now they say in here Django-ticket, that I could avoid the problem of username's max_length being 30, by creating a custom user. Well, I already have a custom user, so it should be easy right? How I tried to do it was:
class CustomUser(AbstractUser, BaseModel):
username = models.CharField(max_length=70, unique=True, db_index=True)
Now when I try to make migrations for changing this field, it results in an error: django.core.exceptions.FieldError: Local field 'username' in class 'CustomUser' clashes with field of similar name from base class 'AbstractUser'
What am I doing wrong? How could I solve this problem? I have data that should be migrated, so I cannot empty database.
Dont try to override username field. Just
class CustomUser(AbstractUser, BaseModel):
#here goes other fields
CustomUser._meta.get_field('username').max_length = 70
But I highly recommend to inherit from AbstractBaseUser instead.
If you want it to be more flexible inherit from AbstractBaseUser instead, you will be able to specify your own username field that way, e.g.
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(
verbose_name=_('date created'),
auto_created=True,
default=timezone.now
)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#specifying-a-custom-user-model
As I understood you can't override any Django ORM model's attribute, nor from AbstractUser, nor from PermissionsMixin classes. So, If you have your own approach to Permissions, Groups(Roles), even if you want another attribute name than user_permissions or groups, then you should inherit from AbstractBaseUser, doing a lot of copy-paste from AbstractUser and inherit your Permission and Group models from django.db.models.Model class as #levi and #Hedde van der Heide suggested.