Is it possible to dockerize Django flatpages? - django

I need to handle Django pages that don't have their own app, and the Django documentation recommends I use flatpages for one-off pages. However, these pages are stored in the database attached to Django, not the filesystem.
This is causing issues because I can't transfer data in the database the same way I can transfer files in the filesystem.
When I run the website through docker-compose, it starts with a fresh postgres image with no data. As a result, the flatpages are left behind anytime I re-run the docker container without migrating all of the data.
The only solution I can think of is simply copying over the flatpages manually every time I bring the website to a new machine. Unfortunately, this seems like a terrible solution because it adds more deployment steps and goes against the ideology of dockerizing websites.
Is there a better solution available?

The (semi-tested) solution I've found is to use a Django data migration, and run the command python manage.py migrate --noinput before starting the server via my docker-compose file.
The data migration itself makes use of the "RunPython" operation, which allows the creation of a hard-coded flatpages through python.
The rough draft of my migration looks like this:
from django.conf import settings
from django.db import migrations, models
from django.contrib.flatpages.models import FlatPage
from django.contrib.sites.models import Site
FLATPAGES = [
{
"title": "Home",
"url": "/home/",
"content": "",
"enable_comments": False,
"template_name":"home.html",
"registration_required": False
},
]
def add_flatpages_data(apps, schema_editor):
site = Site.objects.create(domain='domain.here', name='name.here')
for page_dict in FLATPAGES:
new_page = FlatPage.objects.create(
title=page_dict['title'],
url=page_dict['url'],
content=page_dict['content'],
enable_comments=page_dict['enable_comments'],
template_name=page_dict['template_name'],
registration_required=page_dict['registration_required'],
)
new_page.sites.add(site)
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.RunPython(
add_flatpages_data,
),
]
This isn't pretty, and I don't think it's good whatsoever, but it's the only solution I have found thus far.
As it turns out, Django's fixtures will not work for this application, as Fixtures can only be used for models defined in an app created by the developer. The only reason this is the case is that Django tries to read the fixture's model as "app.model", and thus will not accept the model "django.contrib.flatpages.FlatPage", despite it being just as valid.
I would still like improvements and alternate solutions from others, but I thought I should document my findings.

Related

How many separate apps should I have with my Django app

How many apps should I have in my Django project. For instance, I am building a pet application where there can be owners, pets, veterinarians, etc.
For now sticking to only the 3 I mentioned should I have these as separate apps within my Django project or should I just create one app to handle everything. I will be adding more features as time goes on.
The idea I had was to create a project
django-admin startproject mypets
Then create an application for each:
python manage.py startapp pet
and
python manage.py startapp pet_owner
and
python manage.py startapp veterianarian
As I mentioned before, there are other features I will be adding to my application like photos todo like feature and so on. My concern is that my project is going to get big which is why I want to separate pet_owner and pet each as their own apps. I was thinking this is exactly what I should do but then realized that when I went to mypets.urls.py file and I was thinking about forwarding some requests to a path I quickly realized that I want my route to always have mypets/.
urlpatterns = [
path('admin/', admin.site.urls),
path('mypets/petowner/', include('petowner.urls')),
path('mypets/pet/', include('pet.urls')),
]
but they seem separate in a way that I do not want them to be. For instance. I care about having mypets/petowner/<petowner-id>/pets/ etc. They are going to be very closely related to each other and I will be using relationships in my models. The separation that I want is mostly for organization and readability. I do not want to have a file models.py with a huge amount of code - I think that is ugly and messy.
I plan in the future to use React for my frontend, but because I'm trying to learn Django well I'm going to stick to a full Django app and use django-templates. Not sure if this matters but thought I would mention it just in case.
that is good idea and make project more organized specially for you
if you want to develope your code in the future this works and good for you
if you have problem with urls, now i have a suggestion, you can make a file like url.py in your app which contains your apps urls and then you can back to your main url and give it to urls it seems you know this way
first run your app and make it
now got to app folde and make a file like urls.py
now into that you can write your urls and write your urls in urlpattern as you know
before finish make sure that in the main url.py you have to include other urls that made
urlpatterns = [
path('', include('petowner.urls')),
path('admin/', admin.site.urls),
]
maybe this is good to change your names if involve you too much and write your urls in that app by this way you can be more organized and give your prefix or anything just in your app/urls.py

How to store third party apps migrations in django

I'm fairly new to python and django, and trying to build a simple calendar based on django-scheduler package.
According to django-scheduler docs, a custom base class can be used to add additional fields, managers and such.
So, I used an abstract model to add a new field:
#myproject/customer_calendar/models.py
from django.db import models
from main.models import Customer
class CalendarAbstract(models.Model):
customer = models.OneToOneField(to=Customer, null=True, blank=True, related_name='calendar')
class Meta:
abstract = True
And added this to settings.py
SCHEDULER_BASE_CLASSES = {
'Calendar': ['customer_calendar.models.CalendarAbstract'],
}
Now, if I use makemigrations command, a new migration is created inside scheduler app (which is located in site-packages of the current virtual env), which doesn't allow me to keep track of migrations via VCS.
I've found a couple of solutions:
1) Keep the whole scheduler app inside my project. According to SO it' s considered a bad practice and third-party apps should always be retrieved via pip.
2) Use django setting to store all django-scheduler migrations inside my calendar app
MIGRATION_MODULES = {
'schedule': 'customer_calendar.migrations',
}
The second one looks good to me, but I don't know if it's considered to be a valid solution to this problem.
Is there any other ways to store third-party apps migrations?
The second one looks good to me, but I don't know if it's considered
to be a valid solution to this problem. Is there any other ways to
store third-party apps migrations?
As also stated in this answer, FeinCMS docs recommend the use of MIGRATION_MODULES to monitor the migrations of FeinCMS as a third-party app.
FeinCMS itself does not come with any migrations. It is recommended
that you add migrations for FeinCMS models yourself inside your
project.
...
Create a new folder named migrate in your app with an empty init.py inside.
Add the following configuration to your settings.py:
MIGRATION_MODULES = {
'page': 'yourapp.migrate.page',
'medialibrary': 'yourapp.migrate.medialibrary', }
You must not use migrations as folder name for the FeinCMS migrations,
otherwise Django will get confused.

Django 1.7 - makemigrations creating migration for unmanaged model

I am creating some dynamic Django models in my application and everything seems to be working as expected except for the migration system.
If I create a dynamic Django model and set managed = False, Django's makemigrations command still generates a migration for that new model. The migration looks something like this:
class Migration(migrations.Migration):
dependencies = [
('atom', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='books',
fields=[
],
options={
'db_table': 'books',
'managed': False,
},
bases=(models.Model,),
),
]
If I don't create the migration, when I run python manage.py migrate, I see the following message (in big scary red letters):
Your models have changes that are not yet reflected in a migration, and so won't be applied.
Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
Is there a way to tell the migrations system in Django 1.7 to ignore unmanaged models all together? or perhaps a migrations = False setting in the Meta class of the models?
UPDATE: for clarification, I am using a method to create my dynamic models similar to the ones describe in the following places:
http://dynamic-models.readthedocs.org/en/latest/topics/model.html#topics-model
https://code.djangoproject.com/wiki/DynamicModels
This method is great for generating my dynamic models based on information stored in my Configuration models (https://code.djangoproject.com/wiki/DynamicModels#Adatabase-drivenapproach). I did have to register a signal to clear the django model cache to catch changes to the models when a Configuration instance is changed, but everything seems to be working great, except for the fact that migrations are generated for these models. If I delete one of the configurations and the model is deleted from Django's cache, the migration would need to be updated again, removing the model that it shouldn't care about.
These dynamic models are not used in the application specifically. No where in the code do I refer to a books model (from the example above). They are generated at runtime and used to read information from the legacy tables they provide access to.
The short answer is that Django is not built for this. Making your model "unmanaged" only means Django will not create or delete the table for it -- nothing else.
That said, if you have no regular models alongside these dynamic models in the same app, you can conditionally add the app to INSTALLED_APPS in settings.py:
if not ('makemigrations' in sys.argv or 'migrate' in sys.argv):
INSTALLED_APPS += (
'app_with_dynamic_models',
'another_app_with_dynamic_models',
)
This should make Django ignore the app when creating and running migrations. However, you will eventually have to make and run migrations for the models if you want to use them, since the ability to have apps which do not use migrations is meant to go away in Django 1.9. Could your dynamic models be refactored to use the contenttypes framework?
I suggest you replace the generated migrations.CreateModel operation by one of your own that always reflect the actual model state. This way no state changes should be ever detected.
class CreateDynamicModel(CreateModel):
def __init__(self):
# ... dynamically generate the name, fields, options and bases
super(CreateDynamicModel, self).super(
name=name, fields=fields, options=optins, bases=bases
)
You can probably write a custom database router with the allow_migrate method returning False for your dynamic models. The migrate command will disallow them in that case.
As long as you don't load these dynamic models in any models.py module, makemigrations shouldn't pick them up either.

How to create per-project initial_data fixtures in Django 1.7+

Before Django 1.7 I used to define a per-project fixtures directory in the settings:
FIXTURE_DIRS = ('myproject/fixtures',)
and use that to place my initial_data.json fixture storing the default groups essential for the whole project. This has been working well for me as I could keep the design clean by separating per-project data from app-specific data.
Now with Django 1.7, initial_data fixtures have been deprecated, suggesting to include data migrations together with app's schema migrations; leaving no obvious choice for global per-project initial data.
Moreover the new migrations framework installs all legacy initial data fixtures before executing migrations for the compliant apps (including the django.contrib.auth app). This behavior causes my fixture containing default groups to fail installation, since the auth_group table is not present in the DB yet.
Any suggestions on how to (elegantly) make fixtures run after all the migrations, or at least after the auth app migrations? Or any other ideas to solve this problem?
I find fixtures a great way for providing initial data and would like to have a simple and clean way of declaring them for automatic installation. The new RunPython is just too cumbersome and I consider it an overkill for most purposes; and it seems to be only available for per-app migrations.
If you absolutely want to use fixtures, just use RunPythonand call_command in your data migrations.
from django.db import migrations
from django.core.management import call_command
def add_data(apps, schema_editor):
call_command('loaddata', 'thefixture.json')
def remove_data(apps, schema_editor):
call_command('flush')
class Migration(migrations.Migration):
dependencies = [
('roundtable', '0001_initial'),
]
operations = [
migrations.RunPython(
add_data,
reverse_code=remove_data),
]
However this is recommanded to load data using python code and Django ORM, as you won't have to face integrity issues.
Source.
I recommend using factories instead of fixtures, they are a mess and difficult to maintain, better to use FactoryBoy with Django.

Writing a custom auth system (like the default django auth system), use it to generate tables in DB

Hay all, I've been reading up on middleware and how to use it with a context object. I want to write a simple middleware class which i can use on my own applications, it will essentially be a cut down version of the django one.
The problem i seem to have is that if i have
INSTALLED_APPS = ('django.contrib.my_auth')
in the settings file, all is well. I've also added
MIDDLEWARE_CLASSES = ('django.contrib.my_auth.middleware.MyAuthMiddleware')
in it and everything is fine.
My question is, how would i make my middleware automatically generate tables from a models.py module, much like how the django auth does when i run manage.py syncdb?
thanks
Django auth middleware doesn't generate any tables. Django does it looking through INSTALLED_APPS when you run manage.py syncdb. Therefore all should already be fine.