I have two apps say app1 and app2 and I have models in it.
from app2.models import SecondModel
class FirstModel(models.Model):
first_field = models.ManyToManyField(SecondModel, blank=True)# or Foreign Key
from app1.models import FirstModel
class SecondModel(models.Model):
second_field = models.ForeignKey(FirstModel)
When I do this I get import error.
Could not import name 'FirstModel'
Why is this happening ?
The error is because you have a circular import. It's not possible to for both modules to import from each other.
In this case, you don't need to import the models into each app. Remove the imports, and use a string app_label.ModelName instead.
# app1.models.py
class FirstModel(models.Model):
first_field = models.ManyToManyField('app2.SecondModel')
# app2.models.py
class SecondModel(models.Model):
second_field = models.ForeignKey('app1.FirstModel')
there is a name conflict here .. you defined the FirstModel in your models.py and then defined FirstModel, from the code above, this could be the possible problem. Also, the import error generally mean, there is no FirstModel defined from where you are importing it.
However, a more generic way of doing FKs without import is generally
class FkModel(models.Model):
relationship = models.ManyToManyField('appName.modelName')
where appName is the app from where you are trying to import the model from, and modelName is the model to which you are trying to create the relationship. This helps where you are trying to do something like this.
Lets say your app name is 'app' and you are trying to create a many to many relationship from 1st model to a 2nd model for which the class is declared after the 1st model e.g.
class Model1(models.Model):
first_field = models.ManyToManyField('app.Model1')
class Model2(models.Model):
name = models.CharField(maxlength=256)
that is just put your appname.modelName inside strings :)
also, you have a flaw in your ManyToManyField() declaration i.e. you don't need to define blank in Many to Many. The way db's work under the hood is, they create a 3rd database table just to store many to many relationships.
hope it helps
//mouse.
Related
I read about a solution for the error (write import instead of from ...) but it doesn't work I think because I have a complex folder structure.
Directory structure
quiz/models.py
import apps.courses.models as courses_models
class Quiz(models.Model):
lesson = models.ForeignKey(courses_models.Lesson, on_delete=models.DO_NOTHING) # COURSE APP MODEL IMPORTED
courses/models.py
import apps.quiz.models as quiz_models
class Lesson(models.Model):
...
class UserCompletedMaterial(models.Model):
...
lesson = models.ForeignKey(Lesson)
quiz = models.ForeignKey(quiz_models.Quiz) # QUIZ APP MODEL IMPORTED
How you can see I just can't keep it together or something else..
Because I think the UserCompletedMaterial model is a part of courses app
Both models refer to each other, and this thus means that in order to interpret the former, we need the latter and vice versa.
Django however has a solution to this: you can not only pass a reference to the class as target model for a ForeignKey (or another relation like a OneToOneField or a ManyToManyField), but also through a string.
In case the model is in the same application, you can use a string 'ModelName', in case the model is defined in another installed app, you can work with 'app_name.ModelName'. In this case, we thus can remove the circular import with:
# do not import the `courses.models
class Quiz(models.Model):
lesson = models.ForeignKey(
'courses.Lesson',
on_delete=models.DO_NOTHING
)
# …
I'm defining a class in a Django project and I want a class to have a specific structure.
Versions used:
Django2.2.3
python3.7
I thought about defining the struct as a class and then adding it as an attribute for the main class. But then I am afraid it will create a DB.
This is what I tried:
from django.db import models
class Host(models.Model):
id_host = models.CharField(max_length=20)
[... more attributes here ...]
class Apartment(models.Model):
_id = models.CharField(max_length=20)
host = Host()
[... more attributes here ...]
Any idea on how to do this correctly?
EDIT:
The question is:
How do I code it so that I can define the Host struct and not create a Host DB table while being able to add Host as an Apartment attribute and DO create an Apartment DB?
It is perfectly fine to add custom attributes to your Django model class. It won't create an additional field in your DB. Note that the fields that will be created in your database are managed by migrations anyway. That way you can check which fields will be created when adding or removing attributes from your model class.
In Django 1.7, I couldn't quickly find a simple one-liner to get a related model class from the parent model.
Often these two models are in different files and one already imports the other leading to circular (i.e. broken) imports.
Here's a simple example:
# File: classroom_model.py
from django.db import models
class Classroom(models.Model):
class_code = models.IntegerField()
# File: student_model.py
from classroom_model import Classroom
class Student(models.Model):
classroom = models.ForeignKey(Classroom, related_name="student_set")
```
Here, a desire could be to gain access to the Student model class in Classroom, for example, to write a #classmethod that creates students (e.g. classroom.create_student(name).
Two ways:
1) Simplest way is to change the reference in the ForeignKey definition from a direct model reference to a string, e.g.:
classroom = models.ForeignKey("Classroom")
then remove the import line:
from classroom_model import Classroom
2) The other way is to define in classroom_model.py that:
Student = Classroom.student_set.related.model```
This would be used inside a method where it is used.
If I have myapp/models.py
from django.db import models
class FooBar(models.Model):
x = models.BooleanField()
class Foobar(models.Model):
y = models.BooleanField()
and add myapp to INSTALLED_APPS and do a syncdb, I only get FooBar model converted to a db table. The Foobar model is ignored.
Another strange thing to note is that when we do
from myapp import models
both FooBar and Foobar are present as attributes of models. However,
>>> models.FooBar.__name__
'FooBar'
>>> models.Foobar.__name__
'FooBar'
and both are just interfaces to the db table of FooBar (by default myapp_foobar).
I am asking this question because it seems to me from this that django model names are case insensitive and yet I have not found any documentation stating this and moreover this question was answered to the effect that django model names are case sensitive.
Django model names are not case insensitive, but basically, Django creates a lowercase table name from the app and model names. Thus FooBar, which is in myapp, will generate a myapp_foobar table, and so will Foobar.
Obviously in your example, the names will overlap. Django should warn about clashing table names, but instead, silently ignores clashing models.
To fix this, I suggest you have explicit and distinct table names for your two models. Use the Meta inner class, and set Meta.db_table. See the Django documentation on models Meta.
Example given:
class FooBar(models.Model):
x = models.BooleanField()
class Meta:
db_table = 'myapp_foobar_one'
class Foobar(models.Model):
x = models.BooleanField()
class Meta:
db_table = 'myapp_foobar_two'
In a real world environment, I would never have two similar model names in the same app. It is extremely error-prone.
In referencing models with KeyProperty it seems one has to initialize the model before its referenced
Have I missed some bit of information here?
from google.appengine.ext import ndb
#initialize here
class Vessel(ndb.Model):
pass
class Manifest(ndb.Model):
vessellist = ndb.KeyProperty(Vessel)
class Vessel(ndb.Model):
manifest = ndb.KeyProperty(Manifest)
This is normal behavior. If you want to avoid putting your models in a specific order and you want cross references like that, you can reference a model with a string instead of the model class:
class Manifest(ndb.Model):
vessellist = ndb.KeyProperty('Vessel')
class Vessel(ndb.Model):
manifest = ndb.KeyProperty('Manifest')