Test specific models in Django - python

Is it possible to have a set of models just for testing purposes? The idea is that I've written an app that contains some helper abstract model HelperBase. Now I'd like to provide some models that would inherit from it in order to test it, say DerivedTest1, DerivedTest2. However I wouldn't really like those test models to appear in the production database in the end. I just want their tables to be constructed in the test database. Is it possible and if so - how to do it? I've already tried creating models in the tests.py file but this doesn't seem to work.

You could try creating a whole new app that you only use on your development server.
E.g., if your app is called myapp you would call your testing app myapp_test.
Then in myapp_test's models.py you would from myapp import models and then subclass your models in there.
Then in your settings.py you either just try and remember to comment out the myapp_test application from INSTALLED_APPS when deploying to your production server. Or you can use the local_settings.py methodology to only have the myapp_test included in INSTALLED_APPS on your test machine.

Related

Django 3.2.7 - Detect Currently Running Command From Code

TL;DR:
Is it possible from within a django project to detect which command is currently running?
DETAILS:
We have a Django project (running 3.2.7) running which migrations are a little mixed up.
There is a config model which has been developed way after the initial migrations has been done. This config model is basically a Django ORM model mapped to a DB object and has some caching features (which I will not go into details).
The actual code running on servers never experience any problems, since config model is already provisioned on DB. But right now I'm trying to dockerize the whole project and I need to apply migrations from scratch. When I try to apply the migrations to a fresh db,
It reads settings.py, which contains ROOT_URLCONF variable, that is being directed to another .py file
this .py file contains urlpatterns list, which contains references to various django models
Some of these models includes reference to the config model that I've mentioned earlier. When they are imported, those models are trying to pull configs from this config model, which is not initialized yet on the DB, causing psycopg2.errors.UndefinedTable: relation "core_config" does not exist error.
Model is so deeply integrated in the system so I cannot modify the depending models to use anything non dependent on this model.
My main idea is to detect if makemigrations command is running and returning an empty urlpatterns object if this is the case.
Not sure if this is the best approach, but this is the best I've been able to come up with. If you have any other solution, I'm all ears.

Django with multiple Apps and reusing the same database tables

I am quite new to Django. Right now I am working on a prototype with ~30 database tables. I have understood that with Django you preferably want to have quite small Apps, with limited number of Models.
I want to use the same Models (i.e. database tables) in several different Apps. What is the best practice to achieve this? I am using mysql.
might be quite late for your question.
You may use same model by different app just by refering to it.
First your apps should be under the same project.
Choose one app as 'core' and define your models under it,(I have read that models are better to be at app level)
Then whenever you would like to use a model from that app, import that app's model at the beginning of the code.
Let say we have two apps: app_1 and app_2
and a model defined under app_1/models.py: model_1
In app_2/views.py , import model_1
from app_1.models import model_1

Conditional Django Model Creation

I am writing a app for django which i am planning to publish. This app requires a Bolean Setting variable CONSUMER_REGISTRATION.
Aim of getting this variable is to decide whether to define ConsumerRegistrationModel or not.
This is what I did.
from django.db import models
from django.conf import settings
if getattr(settings, 'CONSUMER_REGISTRATION', False):
class ConsumerRegistration(models.Model):
...
Its working fine. The only Issue i am facing that developers will need to run makemigrations and migrate commands each time they change the variable in settings.
1- Can this work be automated ?. So if they change the variable then some code in django auto run the makemigrations and migrate commands.
2- Or is it perfectly fine to leave this work on developers ??
3- Also I want to ask that is it a good aproach to do this in django ?
The accepted answer doesn't really provide a way to do what the OP is asking, which is to conditionally declare a model.
People may have various reasons for wanting to do this, from not declaring a model at all, to declaring models differently based on settings (it is implied that if you are doing this: you are intend to run the same code base in different places using different settings).
One solution is to put the model in its own app, and conditionally include the app based on a setting:
# Set this your per-project settings:
CONSUMER_REGISTRATION = True
# Set this in the generic settings
INSTALLED_APPS = [...]
if CONSUMER_REGISTRATION:
INSTALLED_APPS.append('consumer_registration') # Models will be loaded.
There's nothing wrong with creating an app which just contains a model.
With regards to "automating" it, the table will be created if migrations are run when the setting is true. It will not delete the table if it is changed to false.
You could simply define the model without any conditionals and tweak your app logic so that instances of ConsumerRegistration model are only interacted with (i.e. created, updated etc.) when the 'CONSUMER_REGISTRATION' flag is set to True.
Running migrations every single time the value of 'CONSUMER_REGISTRATION' is changed would make much more mess than leaving ConsumerRegistration table empty.
As indicated by #dahrens, you could isolate the ConsumerRegistration model along with relevant logic in a separate app, which would only be installed as needed by developers.

Can I have a main models file in a django project?

The Problem
I'm working on a django project in which I need to share the same database models over multiple apps, for example when a user opens a page the page is displayed depending on user settings, which can be changed by the user in a different app than the one which displayes the page
At the moment I've made the browser app which contains most of my models (because it's the one I started with) and I've got other apps like watch_file and user_settings which then import
This is working but I'm noticing that I'm running into organization problems where I'm hopping from file to file to check models and I'm importing all over the place...
My potential Solution
I was thinking about making one big model file somewhere and just importing the models I need for every app in it's own model file, however, I read this question in which someone in the comments stated that generally this is not done
Also I red this question which said that sharing models between apps isn't a good idea at all in regards to organization
The question
In regards to it not being a good idea to make a general model file for all models my project is using, How would I go about organizing it so I don't have to import so many models from different files for an app to work?
Could I create a something like a helper app which isn't displayed but is only used to help other apps by having all models in it's models.py file and importing it frome here in other apps?
NB : when talking about "apps" in the following, I mean "project-specific apps", not "reusable apps".
It's perfectly legal (technically) and hardly avoidable in any non-trivial project to have inter-packages dependencies (Django "apps" are first and foremost python packages), so having one app importing models from another app is definitly not a problem in and by itself. Where it becomes a problem is when you start having circular dependencies (A depends on B which depends on C which depends on A...)
A pattern that usually works fine is to have a "core" app on which all other apps can depend but that must not depends on any other app (except contribs app or third-part apps of course), and a "main" app that can depend on any app but that no other app is allowed to depend on. The core app provides the "foundations" for your project - the basic building blocks that all the project will need - and the main app (which usually has no models at all) is responsible for "top-level integration" of everthing (IOW it's where you put everything that doesn't clearly belongs to another app and "bridges" the other apps features together).
Then you try to keep other apps mostly self-contained except for dependencies on contribs apps, third-part apps and the core app.
Also note that an app does not necessarily have models AND views AND templates AND templatetags etc etc - you can have simple apps defining a couple models or utils, a "frontend" app (somehow similar to the "main" app in concept actually) that's responsible for all your project's views, an "api" app providing a REST api over your other apps models, etc etc.

Does Django's singleton architecture make it unworkable as a standalone ORM in a library?

I like the Django ORM. It's simple, easy to use, and reasonably powerful.
I'm currently developing some internal sites for the VFX company I work for, for which I've used Django. In the meantime, we are developing other python applications and libraries to be used in various contexts in production. There's a number of places in which our core library needs to be interacting with some databases, and using an ORM like Django would really help things. I'm aware of other options like SqlAlchemy or PeeWee, but I'd like to see if Django will work since I use it on the websites and I like its API better.
Using Django as an ORM in a library is tricky (as I explored in a previous question), because Django expects to be used as a website with "apps". In a library, I might want to define any number of data models, which would exist in appropriate places in the library but not inside any Django app (as we're not using any other parts of the framework). So far so good.
I can create a baseclass for my models anywhere in the library as follows:
from django.db import models
from django.apps import apps
import django.conf
django.conf_settings.configure(
DATABASES = ...
)
apps.populate((__name__,))
class LibModel(models.Model):
class Meta:
abstract = True
app_label = __name__
Then anywhere in the library I can create my own models with this baseclass. Since I'm not relying on the "app" for the database names, I need to state them explicitly.
class SpecificModel(LibModel):
# fields go here
class Meta(LibModel.Meta):
db_table = "specific_model_table_name"
This gets around my concern of having to simulate the structure of an "app". The name property in the base class supplies Django with all it needs, and then Django quits whining about not finding an app. The other model files can live wherever they want.
However, there is a glaring use case where this all falls apart. Say that my Django web application wants to use some functionality from the company core python library, which now uses the Django ORM for various things. Since I make a call to django.conf.settings.configure in the library, Django is going to scream about defining the settings more than once when it tries to run the main application.
So basically, a library using the Django ORM is incompatible with Django. Wonderful.
Is there any way around this? I mean, it's a lovely ORM - is it really this impossible to use in a standalone modular way? Is the Django architecture utterly singleton in nature, making this impossible?
*Not a duplicate
I'm trying to have a company python library that uses Django as an ORM. Some of the things that could depend on it might be Django websites themselves. How do I get around Django's singleton insistence on only setting the settings config once? Or is it possible? None of these answers address this!
You can check if django has already been configured.
from django.apps import apps
from django.conf import settings
if not apps.ready:
settings.configure()
django.setup()
When starting Django application - core python library can be configured as separate app an be loaded on startup.
Also, check this answer on dynamic app loading at runtime.
A simple answer is how to initialize Django in a standalone application and do it compatible with Django applications.
import os
import django
if not 'DJANGO_SETTINGS_MODULE' in os.environ:
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysettings'
# # or without DJANGO_SETTINGS_MODULE directly
# from django.conf import settings
# settings.configure(DATABASES=... other...)
django.setup()
# this shouldn't be before DJANGO_SETTINGS_MODULE or settings.configure(...)
from myapp.models import MyModel
# this shouldn't be called before django.setup()
queryset = MyModel.objects.filter(...)
This is more compatible with Django then the answer by Oleg Russkin (where a risk of cyclic dependency at django.setup() is possible if the code is called inside inside a setup() initiated by another similar code or a normal Django project started by manage. It is similar to manage.py where django.setup() is also called internally by execute_from_command_line(sys.argv). The setup initializes all modules related to INSTALLED_APPS all urls modules and consequently all views etc. Many of them are lazy, but still. If any code called by setup() depends on this then neither the condition not apps.ready doesn't help. The setup() is not reentrant and the startup fails.)
Much more general answer
An important concept of Django is to support writing reusable parts of code ("applications" in Django terminology, that can be developed and tested independently. There can be also a tree of dependencies, but uncontrolled mutual dependencies should be avoided if possible) Reusable applications are expected that they can be easier combined to whole project ("project" in Django terminology is with all settings necessary to run it by Python.)
The only unavoidable and useful "singleton" in Django ORM are database connections django.db.connections and django.conf.settings especially INSTALLED_APPS. Only one connection should be used to the same database from the same process or thread.
Django is very configurable. An extreme example: It is possible to write a single file project where all code like settings, models, URL configs and views is defined in one file. That extreme that is probably useful only for some special tests or very short demos or as an exercise. It is even possible to define a project by one file with two "reusable" applications :-)
Django supports also "legacy databases" where the database structure is shared with existing non Django applications and models can be created by inspectdb command. Table names in such models are explicit and don't contain the app name. On the other hand the app name prefix is useful to prevent a possible conflict of the same table names from independent "applications". An important decision is if you can use it as a "legacy" database or a normal Django database.
You can decide between following two solutions or to combine them:
Use e.g. foo_models or bar.models and import all models from them e.g. to app.models and add only that "app" to INSTALLED_APPLICATIONS. This can be viable if it is only for one company and never otherwise and central name assigment is possible. (easiest but little naive)
Use some coarse separation of namespaces to several apps. You should probably use not more than one app with simple names without app name prefix.
Think ahead about migrations**. They will be probably very complicated and very soon impossible if you will create later more projects for the same database and different subsets of database tables without separating them to more apps and without app namespace.
There is really no "singleton" in Django ORM except of django.db.connections itself. If you use more databases you can direct some tables to a specific database by DATABASE_ROUTERS, even with two different models that use the same table name without a prefix.

Categories