Django - Model.py - django

Just a simple question.
After I connect my django app to a remote database, I don't need to use Model.py to create tables in the database, then what is the function for Model.py at that moment?

If you want to use the Django ORM, you'll need to create models in the models.py file that match your remote database. If you don't want django creating or deleting tables on this DB, the managed=False option needs to be set for each model.
https://docs.djangoproject.com/en/1.11/ref/models/options/#managed

As you said after running migrations all tables in models.py file will be created. Later on, if you want to do some database operations, you may be using Django ORM. If you don't have models.py you won't be able to do such operations.
For example:
To create an entry to the table MyModel.
from your_app.models import MyModel
MyModel.objects.create(<field_name>=<value>)
I hope this gives you some idea.

Related

Register SQL-table in Django admin

If I have a PostgresDB that contains both Django models and other SQL tables, is it possible to register these other SQL tables in the Django admin panel?
More details about the setup:
I have a docker-compose setup where Django is running in one container, a Postgres DB in another, and a slack-app in a third container. Django is connected to the DB and the models are registered in the admin panel. This works as intended. The slack-app is also connected to the same DB and has some tables there that are not Django-models. I would like to also access these through the Django admin panel in order to have everything in one place. Is this possible?
You can define unmanaged models in Django. These models will not construct migrations, but will only query the database to select, insert, etc.
Django offers a tool inspectdb [Django-doc] to inspect the database and write the corresponding unamanged models. You thus can use this with:
python3 manage.py inspectdb table1 table2 tablen
It will then write the corresponding models for these tables to the standard output channel, and you thus can copy these in the models.py. In the Meta of these models it will add a managed = False to denote that Django will not migrate these models.
Once you registered these models, you can register a ModelAdmin with:
from django.contrib import admin
from app_name.models import Model1, Model2, Modeln
admin.site.register(Model1)
admin.site.register(Model2)
admin.site.register(Modeln)

How to design the user table in database?

I want to develop a server side of an app that holds users.
Of course I need a table in database holding the user information.
At first I may write
class User(models.Model): # using django models
userid = ...
password = ...
which gives me a database table containing userid and password.
However, I might want to add some attributes (maybe Credit, Birthday...so on) to each user in the future. I just can't think up all of them right now. And I can't know what attributes I would really need in the future.
How can I deal with it?
There's already a user table in Django. This table is automatically create when you first apply the migration with 'manage.py migrate' command.
In database schema, this table is listed as auth_user and you can import it into Django with the following command
from django.contrib.auth.models import User
Django provides a default model for User. you can use it like this.
from django.contrib.auth.models import User
and as per your second query. you can do so by creating another model and adding a ForeignKey or OneToOneField of User model to link it with each user.
class Customuserprofile(models.Model):
user=models.OneToOneField(settings.AUTH_USER_MODEL)
credit=models.CharField()
birthday=models.DateTimeField()
well, if you want to add some field to the User you can use AbstractUser or AbstractBaseUser model read this that explain the differences and give a example https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#abstractbaseuser

Adding a non-null ForeignKey field in Django+South

I use Django and South for my database. Now I want to add a new Model and a field in an existing model, referencing the new model. For example:
class NewModel(models.Model):
# a new model
# ...
class ExistingModel(models.Model):
# ... existing fields
new_field = models.ForeignKey(NewModel) # adding this now
Now South obviously complains that I added a non-null field and asks me to enter a one-off value. But what I really want is to create a new NewModel instance for every existing ExistingModel instance, thus fulfilling the database requirements. Is that possible somehow?
The easiest way to do this is to write a schema migration that makes the column change, and then write a datamigration to correctly fill in the value. Depending on the database you're using you'll have to do this in slightly different ways.
Sqlite
For Sqlite, you can add a sentinel value for the relation and use a datamigration to fill it in without any issue:
0001_schema_migration_add_foreign_key_to_new_model_from_existing_model.py
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
db.add_column('existing_model_table', 'new_model',
self.gf('django.db.models.fields.related.ForeignKey')(default=0, to=orm['appname.new_model']), keep_default=False)
0002_data_migration_for_new_model.py:
class Migration(DataMigration):
def forwards(self, orm):
for m in orm['appname.existing_model'].objects.all():
m.new_model = #custom criteria here
m.save()
This will work just fine, with no issues.
Postgres and MySQL
With MySql, you have to give it a valid default. If 0 isn't actually a valid Foreignkey, you'll get errors telling you so.
You could default to 1, but there are instances where that isn't a valid foreign key (happened to me because we have different environments, and some environments publish to other databases, so the IDs rarely match up (we use UUIDs for cross-database identification, as God intended).
The second issue you get is that South and MySQL don't play well together. Partially because MySQL doesn't have the concept of DDL transactions.
In order to get around some issues you will inevitably face (including the error I mentioned above and from South asking you to mark orm items in a SchemaMigration as no-dry-run), you need to change the above 0001 script to do the following:
0001_schema_migration_add_foreign_key_to_new_model_from_existing_model.py
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
id = 0
if not db.dry_run:
new_model = orm['appname.new_model'].objects.all()[0]
if new_model:
id = new_model.id
db.add_column('existing_model_table', 'new_model',
self.gf('django.db.models.fields.related.ForeignKey')(default=id, to=orm['appname.new_model']), keep_default=False)
And then you can run the 0002_data_migration_for_new_model.py file as normal.
I advise using the same example above for Postgres and for MySql. I don't remember any issues offhand with Postgres with the first example, but I'm certain the second example works for both (tested).
You want a data migration to supplement your schema migration in this scenario.
South has a nice step by step tutorial on how to achieve this in the docs, here.
It's not uncommon in South to have the desired outcome spread over two or three schema/data migrations as its not always possible to do it in one big hit (sometimes depends on the underlying db if it will tolerate adding a non null column with no default). So in this case you might add a schema migration that has a default, then a data migration with your object manipulation then a final schema migration.

Utility of managed=False option in Django models

In django models we have option named managed which can be set True or False
According to documentation the only difference this option makes is whether table will be managed by django or not. Is management by django or by us makes any difference?
Is there any pros and cons of using one option rather than other?
I mean why would we opt for managed=False? Will it give some extra control or power which affects my code?
The main reason for using managed=False is if your model is backed by something like a database view, instead of a table - so you don't want Django to issue CREATE TABLE commands when you run syncdb.
Right from Django docs:
managed=False is useful if the model represents an existing table or a database view that has been created by some other means. This is the only difference when managed=False. All other aspects of model handling are exactly the same as normal
When ever we create the django model, the managed=True implicitly is
true by default. As we know that when we run python manage.py makemigrations the migration file(which we can say a db view) is
created in migration folder of the app and to apply that migration i.e
creates the table in db or we can say schema.
So by managed=False, we restrict Django to create table(scheme, update
the schema of the table) of that model or its fields specified in
migration file.
Why we use its?
case1: Sometime we use two db for the project for
example we have db1(default) and db2, so we don't want particular
model to be create the schema or table in db1 so we can this or we can
customize the db view.
case2. In django ORM, the db table is tied to django ORM model, It
help tie a database view to bind with a django ORM model.
Can also go through the link:
We can add our raw sql for db view in migration file.
The raw sql in migration look like: In 0001_initial.py
from future import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.RunSQL(
CREATE OR REPLACE VIEW app_test AS
SELECT row_number() OVER () as id,
ci.user_id,
ci.company_id,
),
]
Above code is just for overview of the looking of the migration file, can go through above link for brief.

Django admin - instance needs to have a primary key value before a many-to-many relationship can be used

edit: I wasn't clear before, I am saving my object in the django admin panel, not in a view. Even when I save the object with no many-to-many relationships I still get the error.
I have a model called TogglDetails that has a ForeignKey relationship with the standard django User model and a MayToManyField relationship with a model named Tag. I have registered my models with django admin but when I try to save a TogglDetails instance I get the error in the title.
Here are my models:
class Tag(models.Model):
name = models.CharField(max_length=30)
def __unicode__(self):
return self.name
class TogglDetails(models.Model):
token = models.CharField(max_length=100)
user = models.ForeignKey(User)
tags = models.ManyToManyField(Tag, blank=True, null=True)
def __unicode__(self):
return self.user.username
class Meta:
verbose_name_plural = "toggl details"
As far as I can tell, there should be no issues with my models and django admin should just save the instance without any issues. Is there something obvious that I have missed?
I am using Django 1.3
The answer to my question was this: Postgres sequences without an 'owned by' attribute do not return an id in Django 1.3
The sequences in my postgres database did not have the "Owned by" attribute set and so did not return an id when a new entry was saved to the db.
As stated by other users:
Postgres sequences without an 'owned by' attribute do not return an id in Django 1.3
The sequences in my postgres database did not have the "Owned by" attribute set and so did not return an id when a new entry was saved to the db
In addition:
This is most likely caused by a backwards incompatible change that renders some primary key types in custom models beyond reach for Django 1.3. See Django trac tickets https://code.djangoproject.com/ticket/13295 and http://code.djangoproject.com/ticket/15682 for more information.
I solved the problem by running the follow commands for the affected tables/sequences.
Specifically running the command:
manage.py dbshell
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
change tablename_colname_seq and tablename.colname
Don't let us guess and add the Error message to your question, this gives most information about where it fails.
Have you imported the User model?
from django.contrib.auth.models import User
I've had this problem as well and the only thing I could do was make the M2M fields blank and not set them until I hit Save and Continue Editing.
I think this just may be a framework wart, as you will notice the User section of the Admin site also has a very strict "You can only edit these fields until you save the model".
So my recommendation is to adopt that scheme, and hide the M2M form field until the model has a Primary Key.
I tried Django 1.3 using CPython, with different database setups. I copy-pasted the models from the question, and did some changes: first I added
from django.contrib.auth.models import User
at the top of the file and I put the reference to Tag between quotes. That shouldn't make any difference. Further, I created the following admin.py:
from django.contrib import admin
import models
admin.site.register(models.Tag)
admin.site.register(models.TogglDetails)
For Sqlite3, the problem described doesn't occur, neither for MySQL. So I tried PostgreSQL, with the postgresql_psycopg2 back end. Same thing: I can't reproduce the error.
So as far as I can figure, there's nothing wrong with the code in the question. The problem must be elsewhere.