I've looked into the source code for some django model fields, in this case DateTimeField. In the tutorial for Django, we are taught to create a DateTimeField like this:
from django.db import models
field = models.DateTimeField()
But looking in the source code, the file where DateTimeField is defined is django/db/models/fields. So, intuitively, if I were to import the field, I would write from django.db.models.fields import DateTimeField.
Do you see the difference? In the tutorial, they import it from django/db/models, while it looks like from the location of the source code that it actually resides in django/db/models/fields. Why doesn't the tutorial way of importing DateTimeField crash?
The fields are imported in django/db/models/__init__.py
Take a look at the source code.
Possibly relevant: What is init.py for?
Related
I am building an app that displays different courses. For each course there is a list of the different classes it has.
Some courses have two classes, some have eight, some have just one or in the future some courses may have 10 classes. It's up to the app's administrator when they register a new course
class Curso(models.Model):
clases = models.IntegerField(default=1)
content = ArrayField(models.CharField(max_length=30),blank=False)
This model will only be for the administrator.
I want to store the different classes (just their names) in an array. But there's no need to show 8+ fields if the admin is just going to fill one in... Or is that the correct approach?
I want the admin to have an integer field where she types in how many classes the course has and depending on that the array fields will be displayed.
I understand ArrayField has a size attribute where I can say how long the array is. Right? So my question is:
Is there a way to dynamically change the array size depending on what the admin types in in the "clases" field?
I need this to work in the admin app. I am new to Django and I'm finding the admin app a little bit hard to manipulate.
Well I did my research. And this is how it turned out:
models.py
from django.db import models
from django_better_admin_arrayfield.models.fields import ArrayField
# Create your models here.
class Course(models.Model):
...
clases = ArrayField(models.CharField(max_length=10),null=True,blank=True, size=8)
...
Turns out I just needed to use ArrayField with django-better-admin-arrayfield
It doesn't do exactly what I described in this question, but it works just as fine (even better) to visually edit the arrayfield in the admin page
Here's the repository django-better-admin-arrayfield
You just need to pip install it and then add it to your settings.py installed apps
INSTALLED_APPS = [
...
'django_better_admin_arrayfield',
...
In admin.py
from django.contrib import admin
from .models import Course
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
#admin.register(Course)
class CursoAdmin(admin.ModelAdmin, DynamicArrayMixin):
...
And that was it! makemigrations and migrate and... It didn't work. The problem was the add another button wasn't working. So I read the issues in the repo and someone wrote you should run collectstatic and it worked!!
Shout out to #nbeuchat, whoever that is, that who's answer in in this stackoverflow post was the only thing that helped me get out of this problem
I have a question to the AUTH_USER_MODEL in Django:
https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model
The default value is auth.User. However, the actual model is in auth.models.User. How does Django find the correct class?
I am asking because when I usually use models in Django, I have to write from myapp.models import MyModel. So, why do I not need models in auth.User for AUTH_USER_MODEL?
Can some explain me that or show the code that uses it?
Well you define models in the models.py file of an app. So that means that the module in which you stored the model class is app.models. Therefore the import reads:
from app.models import MyModel
Django has in essence nothing to do with this: this is how Python loads modules and classes from these module(s).
Django however loads - when you for example run the server - the apps that are located in the INSTALLED_APPS list of the settings file (usually settings.py), and thus constructs a "register" where it stores Django models, and it names them in a uniform way: app_name.ModelName. There is no reason to specify models here, since models are defined in models.py, and it thus would only introduce "noise".
You can obtain a reference to the model class with apps.get_model [Django-doc]
from django.apps import apps
apps.get_model('app_name', 'ModelName')
It thus then checks the registers of the loaded models, and returns a reference to the model.
Linking through a string is useful (and sometimes required) when there is cyclic referencing. For example if you have two models A and B, and A refers to BandBthroughA(for example withForeignKeys), then one of the two models is defined first. This means that if you defineAfirst, it can not refer to theB` class itself, since at that point it does not yet exists. In Django, one then specifies the model through a string. The Django system will then first load the models, and then "tie the knot": resolve the references by replacing the strings with a reference to the actual model class.
Suppose you had a Django model:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
And you migrate it to:
from django.db import models
class Person(models.Model):
both_names = models.CharField(max_length=30)
You might write a data migration for this case (or mine, not the above, but similar and not cogent to the question) and you would definitely want to test it.
I used call_command('migrate', app, state) to roll the database back to the old state and then I thought I'd just use a historic ORM of Person to instantiate some Person objects, then do the migration, then make some assertions to check if my data migration went properly.
In South, you would just call up the old ORM by Migration. How does one do this in Django 1.8?
I'm basing my strategy on this documentation: https://micknelson.wordpress.com/2013/03/01/testing-django-migrations/
And I'm hoping to find the implementation for Django's historic-models: https://docs.djangoproject.com/en/1.8/topics/migrations/#historical-models
To restate the question - How would I get the 'old' state of Person, such that I would create a person like so: Person(first_name='bob', last_name='jones') - for testing purposes.
The public API doesn't provide any means to get historical models outside of a migration. However, you can get it using the following code:
from django.db import connection
from django.db.migrations.loader import MigrationLoader
loader = MigrationLoader(connection)
state = loader.project_state(loader.applied_migrations)
apps = state.apps
apps is the same object that is passed to the function in a RunPython operation. You can get a historical model for the currently applied migrations using apps.get_model('<app_label>', '<ModelName>').
This should work in 1.8 and 1.9. It may or may not work in future versions, though I see little reason why this part of the API should change anytime soon.
For Django 3.0 and 3.1 , the solution is mostly the same as the answer from #knbk , except the input argument to project_state() is simply a tuple like ('<APP_LABEL>', '<MIGRATION_NAME>') instead of entire applied_migrations dictionary.
you can get the state from initial migration to the specific committed migration of specified application, by directly specifying <APP_LABEL> or <MIGRATION_NAME> like this :
from django.db import connection
from django.db.migrations.loader import MigrationLoader
loader = MigrationLoader(connection)
state = loader.project_state(('your_app_label', '0023_alter_some_fields'))
apps = state.apps
Note that the code above cannot be used when running migration commands (e.g. makemigrations, sqlmigrate, migrate), otherwise it will cause recursive callstack error.
I am outsourcing my models into packages in order to have a better overview. So the models.py of my app main looks like
from django.db import models
from models import *
And the actual models are in models/user.py, ...
So when I go back to prepare a migration:
python manage.py makemigrations main
Django won't detect any changes. Why?
I had the same problem with migrating my models. so i changed the import methodology and instead of
from models import *
i tried this
from models.user import User, Device, ...
and it worked
Django looks into 'appname/models.py'. If you want this structure, you can use 'appname/user/models.py' and in INSTALLED_APPS 'appname.user', but it's better to use flat design: 'appname/models.py', 'user/models.py', ...
On documentation it has been said that each model is a python subclass of models.Model class that is inside django folder followed by db folder. When i look inside my django folder i see a db folder which was expected and inside my db folder i see models folder which contains lot of files. But I was expecting a models.py package which contains Model class. So my doubt is from where does this models.Model class come from?
This might be not a top level question but I am hopeful someone here will certainly help.
Nope it's not magic it's django , it does exist if you go to the django's source code, you can see that the Model class exists, But in that way don't you had to import models in this way??:
from django.db.models.base import Model
Yes you can do it in that way, But django does it for you in the models/__init__ file, so the only thing you have to do is:
from django.db import models
models refers to the models folder inside django.db but when you import it, it brings you all the things that are inse the models/____init__.py file, I recommend you to read this