I have the following code in my models.py file:
from django.db import models
from django.db.models import permalink
class Page(models.Model):
name = models.CharField(max_length=100,db_index=True, unique=True)
slug = models.SlugField(max_length=100,db_index=True, unique=True)
def __unicode__(self):
return '%s' % self.name
class Category(models.Model):
name = models.CharField(max_length=100, db_index=True, unique=True)
slug = models.SlugField(max_length=100, db_index=True, unique=True)
def __unicode__(self):
return '%s' % self.name
class Post(models.Model):
title = models.CharField(max_length=100, unique=True, db_index=True)
body = models.TextField()
post_date = models.DateField(db_index = True, auto_now_add=True)
category = models.ForeignKey('board.Category')
page = models.ForeignKey('board.Page')
def __unicode__(self):
return '%s' % self.title
#permalink
def get_absolute_url(self):
return "/%i/%i" % Page.slug, self.id
When I try to add a Post object in the admin page (I configured the admin.py too), I get the following error:
no such column: board_category.name
I did my research and tried dropping the table and doing syncdb again but somehow it still shows this error.
So I listed my tables:
CREATE TABLE "board_page" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(100) NOT NULL UNIQUE,
"slug" varchar(100) NOT NULL UNIQUE
)
;
CREATE TABLE "board_category" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(100) NOT NULL UNIQUE,
"slug" varchar(100) NOT NULL UNIQUE
)
;
CREATE TABLE "board_post" (
"id" integer NOT NULL PRIMARY KEY,
"title" varchar(100) NOT NULL UNIQUE,
"body" text NOT NULL,
"post_date" date NOT NULL,
"category_id" integer NOT NULL REFERENCES "board_category" ("id"),
"page_id" integer NOT NULL REFERENCES "board_page" ("id")
)
;
CREATE INDEX "board_post_896eb94b" ON "board_post" ("post_date");
CREATE INDEX "board_post_6f33f001" ON "board_post" ("category_id");
CREATE INDEX "board_post_3fb9c94f" ON "board_post" ("page_id");
I'm not exactly an expert in SQL but I can clearly see that the board_page.name column exists so I really have no idea why this is giving me an error.
And the strangest thing is that adding another page or category actually works....
--EDIT
from django.contrib import admin
from board.models import Page, Post, Category
class PageAdmin(admin.ModelAdmin):
#fields = ['name','slug']
pass
class PostAdmin(admin.ModelAdmin):
#fields = ['title','body','category','page']
pass
class CategoryAdmin(admin.ModelAdmin):
#fields = ['name','slug']
pass
admin.site.register(Page, PageAdmin)
admin.site.register(Post, PostAdmin)
admin.site.register(Category, CategoryAdmin)
syncdb will only create tables for models which have not yet been installed. It will never issue ALTER TABLE statements to match changes made to a model class after installation.
better use South to migrate the changes of your models.
first migration with:
python manage.py schemamigration yourapp --initial
python manage.py migrate yourapp
other migrations:
python manage.py schemamigration yourapp --auto
python manage.py migrate yourapp
If you add something to your models and after that you did not sync, this happens.
If you are in beginning for your project, I recommend to remove your db and recreate it and then:
python manage.py syncdb
Otherwise use South.
http://south.readthedocs.org/en/latest/
It's interesting but sometimes rebooting the server helps. It worked for me a few times in past.
Related
I am making a notes app. When I try to create a foreign key to link the user and its notes, im getting an error while using
python manage.py migrate
. I am very new to foreign keys, I looked at the Django docs, this is how they created a foreign key.
here's the code :
from django.db import models
class User(models.Model):
username = models.CharField(max_length=50)
email = models.EmailField(max_length=50)
class Note(models.Model):
body = models.TextField(null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.body[0:50]
here's the error :
django.db.utils.IntegrityError: NOT NULL constraint failed: new__api_note.author_id
Your issue is that that there are existing notes in the database that do not have a author_id field, but you have not set a default value and neither allowed to to be kept blank. Thus it's a IntegrityError to add the field.
You can solve this in 2 ways:
Allow the field to be blank
Delete the last migration in your migrations folder
Edit the author field like this:
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
Run makemigrations and migrate
Set a default value for the field
Delete the last migration from the migrations folder. You can also edit it but simply deleting it is easiest
Run makemigrations again
During make migration, it will prompt you if you want to provide a default value for the field. Select "Provie a one of value for now"
Type models.User.objects.all().first() or alternatively some other "defalt" author for existing notes
Run migrate
You can also solve the problem by removing all existing notes from the database
I have the following model
from django.db import models
class Todo(models.Model):
content = models.CharField(max_length=100)
created_at_one: models.DateField(auto_now_add=True)
finished_at: models.DateField(null=True)
is_completed: models.BooleanField(default=False)
list = models.ForeignKey(
"TodoList", related_name="todos", on_delete=models.CASCADE)
class TodoList(models.Model):
title: models.CharField(max_length=20)
created_at: models.DateField(auto_now_add=True)
Then when I run python manage.py makemigrations and python3 manage.py migrate, there is no error. But when I check the tables created, some columns are missing.
I run .schema app_todo to check the tables of Todo
CREATE TABLE IF NOT EXISTS "app_todo" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "content" varchar(100) NOT NULL, "list_id" bigint NOT NULL REFERENCES "app_todolist" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "app_todo_list_id_c59d99ef" ON "app_todo" ("list_id");
Only id, content and list_id are created and three columns missing.
For TodoList:
CREATE TABLE IF NOT EXISTS "app_todolist" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT);
title and create_at are missing.
Please let me know if there is additional information that I should provide.
Thanks a lot!
You probably made a typo write writing your model. You must not use : but = when declaring your fields. It should be :
from django.db import models
class Todo(models.Model):
content = models.CharField(max_length=100)
created_at_one = models.DateField(auto_now_add=True)
finished_at = models.DateField(null=True)
is_completed = models.BooleanField(default=False)
list = models.ForeignKey(
"TodoList", related_name="todos", on_delete=models.CASCADE)
class TodoList(models.Model):
title = models.CharField(max_length=20)
created_at = models.DateField(auto_now_add=True)
When using : you may create some class attributes but that are not considered by Django for building database models.
While creating item I got this error, though I can see category_id at sqlall:
table items_item has no column named category_id
migration commands:
$ python manage.py makemigrations items
No changes detected
$ python manage.py migrate
Running migrations:
No migrations to apply.
model.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=200)
# Create your models here.
class Item(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
image = models.ImageField(upload_to="item_images")
category = models.ForeignKey(Category)
show_in_front_page= models.BooleanField(default=True)
always_show_in_front_page= models.BooleanField(default=True)
is_trending=models.BooleanField(default=True)
sqlall
# $ python manage.py sqlall items
BEGIN;
CREATE TABLE "items_category" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(200) NOT NULL
)
;
CREATE TABLE "items_item" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(200) NOT NULL,
"description" text,
"image" varchar(100) NOT NULL,
"category_id" integer NOT NULL REFERENCES "items_category" ("id"),
"show_in_front_page" bool NOT NULL,
"always_show_in_front_page" bool NOT NULL,
"is_trending" bool NOT NULL
)
;
CREATE INDEX "items_item_6f33f001" ON "items_item" ("category_id");
COMMIT;
admin.py
from django.contrib import admin
# Register your models here.
from .models import Item, Category
admin.site.register(Item)
admin.site.register(Category)
If the category_id column is already in an applied migration file, but hasn't been created in the database., then the easiest fix would be to add the column manually. It's easy to work out the SQL from your sqlall output above.
./manage.py dbshell # open a db shell
# Add the column
ALTER TABLE items_item ADD COLUMN "category_id" integer NOT NULL REFERENCES "items_category" ("id");
# Add the index
CREATE INDEX "items_item_6f33f001" ON "items_item" ("category_id");
try deleting your db.sqlite3 file.
Then run makemigrations and migrate (the sqlite file will generates automatically).
I am curious about Django database model pk.
Is there any difference this
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
category_name = models.CharField(max_length=50)
between this?
class Category(models.Model):
category_name = models.CharField(max_length=50)
Are the same things AutoField with primary_key and default pk?
Yes, the difference is, the column name in the database for the primary key is category_id and in the second case is id.
One way you can make the second example emulate the first one is:
class Category(models.Model):
category_name = models.CharField(max_length=50)
#property
def category_id(self):
return self.id
From the documentation,
AutoField
An IntegerField that automatically increments according to available IDs. You usually won’t need to use this directly; a primary key field will automatically be added to your model if you don’t specify otherwise
The difference is field name.
For example, I definded the model "Category" with the field "category_id":
# "myapp/models.py"
from django.db import models
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
category_name = models.CharField(max_length=50)
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Now, I opened "db.sqlite3" then the field name is "category_id":
Next, I definded the model "Category" without the field "category_id":
# "myapp/models.py"
from django.db import models
class Category(models.Model):
category_name = models.CharField(max_length=50)
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Now, I opened "db.sqlite3" then the field name is "id":
I've written a couple of tests for really simple blog app, but the many to many relationship fails when I run the test: ./manage.py test myblog
DatabaseError: no such table: myblog_post_tag
Yet when I do ./manage.py sql myblog:
BEGIN;
CREATE TABLE "myblog_tag" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(50) NOT NULL
)
;
CREATE TABLE "myblog_post_tag" (
"id" integer NOT NULL PRIMARY KEY,
"post_id" integer NOT NULL,
"tag_id" integer NOT NULL REFERENCES "myblog_tag" ("id"),
UNIQUE ("post_id", "tag_id")
)
;
CREATE TABLE "myblog_post" (
"id" integer NOT NULL PRIMARY KEY,
"title" varchar(200) NOT NULL,
"pub_date" datetime NOT NULL,
"content" text NOT NULL
)
;
COMMIT;
It does create a table, yet it fails to do so while testing? Any help is appreciated.
Here's my test:
class TagModelTest(TestCase):
def test_create_tags_for_posts(self):
# tests tagging posts, postodd will have tags 1 & 3, posteven will be 2 & 4
postodd = Post(
title="testing odd tags",
pub_date=timezone.now(),
content='''hello everybody, we are testing some tagging
functionality here. This post should have odd tags.''',
)
posteven = Post(
title="test even tags",
pub_date=timezone.now(),
content ='''hello everybody, we are testing some tagging
functionality here. This post should have even tags.''',
)
#save them to db
postodd.save()
posteven.save()
# create the tags
tag1 = Tag(name="1")
tag2 = Tag(name="2")
tag3 = Tag(name="3")
tag4 = Tag(name="4")
# save all tags to db
tag1.save()
tag2.save()
tag3.save()
tag4.save()
# create the many2many relationship
postodd.tag.add(tag1)
And my models.py if needed:
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Post(models.Model):
tag = models.ManyToManyField(Tag)
title = models.CharField(max_length=200)
pub_date = models.DateTimeField(verbose_name="Date published")
content = models.TextField()
def __unicode__(self):
return self.title
./manage.py sql myblog does not execute the SQL, it just outputs what it would execute if you ran syncdb.
In this case, it seems the table is missing from your db.
If this was a result of a modification to an existing app; for example you just added a new field to your model; then running syncdb won't affect the changes to your database. syncdb doesn't do any destructive operations (like adding or dropping tables or columns).
In this case you can manually run the query to add the column; or drop and recreate your tables with syncdb.
Since this is a common problem most people use a data migration tool like south to handle these changes for you. South will manage these small changes intelligently.