Django recursive imports - django

I have two apps: pt and tasks.
pt.models has a Member model.
tasks.models has a Filters model.
Member model has a foreign key to Filters model (one for a member).
Filters has M2M field to Member as it holds some kind of filtering settings.
So, I must recursively import both models to get everything synced what is impossible in Python.
Any ideas?

Again, circular imports are not an error in Python, only using names that don't yet exist when doing so.
From the docs:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself...

Related

Django CMS copy model instance issue

I have some issue with Django CMS 3.0 plugin model copy_relations function.
Example from documentation
def copy_relations(self, oldinstance):
for associated_item in oldinstance.associated_item.all():
# instance.pk = None; instance.pk.save() is the slightly odd but
# standard Django way of copying a saved model instance
associated_item.pk = None
associated_item.plugin = self
associated_item.save()
is not working and CMS is only modifying instance of plugin model. In this example I need to add associated_item.id = None for it to work.
This is not my first Django CMS project, but is first in 3.0. In previous versions I did follow documentation and everything was ok, but not this time.
The question is: is the documentation not up-to-date or I did something wrong on the way when creating models?
edit:
Here is where I found how to make Django CMS to save a copy of model instance:
Due to how inheritance works, you have to set both ``pk`` and ``id`` to None
I need to do this for all models with copy_relations, and I want to know why is this required.
Obviously in your case associated_item points to a model which inherits from another model. There are two types of model inheritance in Django: abstract and multi-table.
In the case of abstract inheritance, the base model is abstract, i.e. it is not in the database and just serves as a template for the models which inherit from it.
In the case of multi-table inheritance, all of the models are in DB, with submodels linked to the base model via a ForeignKey.
For regular models .pk and .id are one and the same thing (you can even check it with my_model.pk is my_model.id), while for multi-table submodels .id is the id field of the base model, and .pk is the ForeignKey used to connect the submodel to the base model. In fact, the numeric value of .pk and .id is still the same (because .pk points to .id), but nonetheless they are two separate columns in the DB. In my opinion this Django design decision is somewhat inconsistent, but that's what we have.
That's why you need to set both fields to None for Django to lose track of the model and see it as a new model instance.

fields automatically added by django

By default, Django automatically gives each model an id field.
Are there any additional fields django's ORM adds automatically? Perhaps in specific cases?
There are only 2 other situations I can think of where fields are automatically created. One is when sub-classing another model. The sub-class will inherit the parent's fields, see here. The other is a Many-to-Many relationship. For a M2M relationship not only will a field get created but an entire intermediate table. Again, the relevant docs
Also, you can avoid having Django create the id field if you specify primary=True for the field you want to use as the primary key. See here
There are some other model/DB naming conventions as well. For example, the actual database table names will be prefixed with the Django app name that contains them plus an underscore. For example, a model named Author in an app named library will get called library_author. I'm sure there are other examples as well, so this is not an exhaustive list.

Get the ORM that is created by Django

From the Django docs:
How are the backward relationships possible?
Other object-relational mappers require you to define relationships on
both sides. The Django developers believe this is a violation of the
DRY (Don’t Repeat Yourself) principle, so Django only requires you to
define the relationship on one end.
But how is this possible, given that a model class doesn’t know which
other model classes are related to it until those other model classes
are loaded?
The answer lies in the INSTALLED_APPS setting. The first time any
model is loaded, Django iterates over every model in INSTALLED_APPS
and creates the backward relationships in memory as needed.
Essentially, one of the functions of INSTALLED_APPS is to tell Django
the entire model domain.
Is there a way to get this ORM model? I am trying to debug some reverse relations that are not automagically created and it would really help to see the whole ORM Django has created.
There is no specific ORM "Model", however there are a few things that may help you.
from django.db.models.loading import get_models
get_models() will return you a list of every registered model, this list is what the mechanism that you are describing loops over.
YourModel._meta.get_all_related_objects_with_model()
This function loops over every field in every registered model and finds and returns any reverse relations to your YourModel.
The Options class from django.db.models.options (YourModel._meta is an Options object) is a good place to look around for this stuff.
Django doesn't "create" an ORM so the question makes no sense. If you want to know what properties the ORM adds to your model classes to support backward relationships then you can
open a django shell, import your models and inspect them
read the source code (hey, it's open source isn't it ?)
if that's not enough, add breakpoints at appropriate places and run the whole thing thru the debugger

Django (South): change model application

I have defined some models within an application, call it "blog".
djangoproject
/blog
models.py
I now want to change the models location, for example put them here:
djangoproject
/blog
xxx
/all_models
models.py
From the code point of view, this is pretty trivial, but the I guess there will be problems on the database since all the tables Django and South created are now called blog_posts blog_comments, Django relies on this naming convention and I don't want to lose the data already present in the database.
How to do this?
The easiest thing is not to bother changing the tables at all, but the code. Inside the Meta class of each of your models, put the declaration db_table = "blog_tablename", and Django will find them without problems.
You can solve this in two ways.
The first and easier one is to provide a db_table in Meta class of each of your models. The other is create a migration to apply the change.
As far as I know south doesn't support table rename, so you should do it as a three way migration:
Move de models, and create migration (now you have both tables old and new)
Create a data migration and iterate over the former table, copying objects to later
Remove the former model, and create a migration for it.
You can read a little bit more about the second way in south docs

Third-party-app for merging Django user objects?

I need to merge two users in a Django database.
So I wonder if there is any simple way (maybe a dedicated app) to do that?
For example:
We have user_a and user_b and some models that have foreign keys to the User model (Books, Interests, Teams and so on…).
By merging users, I want to delete the object user_b and to set all foreign keys pointing to this object to point to user_a. And – this is my main concern – I want the objects that need to be changed because they reference the to-be-deleted object to be determined automatically without having to specify a list of those Models and foreign key fields in them manually.
Is this already implemented and I'm reinventing the wheel?
Is this possible?
If not, please show me the way to do it: how can I build a list of Django models that have a foreign key to a specific model (User in my case) in runtime?
Thank you for your time.
I found this snippet http://djangosnippets.org/snippets/2283/ . I'm going to have to modify it though, to make it recursive. I will share my code once I'm done.
With Django 1.8 and beyond, you could achieve this robustly using the Model _meta API.
Specifically, you could use Options.get_fields. This will even let you handle generic relations.
You'll need to consider for each related field whether you want to add or replace on merge. This decision depends on your application logic and corresponding schema choices.
u = User.objects.get(pk=123)
related_fields = [
f for f in u._meta.get_fields()
if (f.one_to_many or f.one_to_one)
and not f.concrete
]
for f in related_fields:
# use field's attributes to perform an update