ndb python appengine odd behavior models referencing each other - python

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')

Related

Django models how to fix circular import error?

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
)
# …

Defining a struct as a class attribute

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.

Is it possible for a function to reference the class on which it's called?

I have some models defined in Django such as these:
class Post(models.Model):
text = models.CharField(max_length=50)
class Thread(models.Model):
title = models.CharField(max_length=50)
And I would like to have an external function that, called inside either of these classes, does something related to the class on which it was called.
For example, a ListAll() function that, called inside Post(), lists all Post objects, but called inside Thread, lists all Thread objects.
How would I do this? I've seen replies using __this__ but apparently that references specific class instances, which confuses me a little.
Thank you.
This is a job for a mixin, which can be added to any class.
class ListAll:
def list_all(self):
return self.__class__.objects.all()
Add it to the class:
class Post(ListAll, models.Model):
...
And use it:
my_post_obj.list_all()
I hope this is an example though, as it would be far better to just pass the model class itself into wherever you want to list the objects.
You can use functions inside the model and those can be called with class objects
class Thread(models.Model):
title = models.CharField(max_length=50)
def listAll(self):
return self.objects.all() # a function that would return all objects
As per comments If you have requirements of using a single function for many models then you can load a model dynamically by its name. I won't say that its recommended or anything but it works perfectly.
import importlib
model_module = importlib.import_module('app_name.models.models')
# remember this example refers to loading a module not its class so if you
# have a file models.py containing all the models then this should be perfect
model_object = model_module.model_name # now you have loaded the model
data = model_object.objects.all() # apply whatever you want now

django models relation to two models before saving

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.

Django: Get related model class from parent 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.

Categories

Resources