Django - Create Category Views doesn't create Column - python

I am doing this tutorial tangowithdjango 5 Models and databases
In the exercises it asks to create a views and likes column with default=0 in the categories. Then to use population script to update them with values.
Direct quote from site
Update the Category model to include the additional attributes, views
and likes where the default value is zero.
So I have gone and created the categories in models.py
from django.db import models
from django.template.defaultfilters import default
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
class Meta:
verbose_name_plural = "Categories"
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
Then I sync.db
However the columns aren't creating I get this error from the view.
Exception Type: DatabaseError at /admin/rango/category/
Exception Value: no such column: rango_category.views
What is wrong with how I have created them? Do I have to remove all my database tables and recreate them?
Edit: The solution to Incorrect Duplicate doesn't resolve the issue, as well as my answer I thought would. Deleting the database and re-syncing didn't resolve the issue with creating the population script.
The sql appears to be ok I am unsure what is wrong.
BEGIN;
CREATE TABLE "rango_category" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(128) NOT NULL UNIQUE,
"views" integer NOT NULL,
"likes" integer NOT NULL
)
;
CREATE TABLE "rango_page" (
"id" integer NOT NULL PRIMARY KEY,
"category_id" integer NOT NULL REFERENCES "rango_category" ("id"),
"title" varchar(128) NOT NULL,
"url" varchar(200) NOT NULL,
"views" integer NOT NULL
)
;
COMMIT;
Finished "/home/sayth/workspace/tango_project/manage.py sql rango" execution.
Even re deleting database and redesigning and recreating models doesn't reolved.
BEGIN;
CREATE TABLE "rango_category" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(128) NOT NULL UNIQUE
)
;
CREATE TABLE "rango_page" (
"id" integer NOT NULL PRIMARY KEY,
"category_id" integer NOT NULL REFERENCES "rango_category" ("id"),
"title" varchar(128) NOT NULL,
"url" varchar(200) NOT NULL,
"views" integer NOT NULL,
"likes" integer NOT NULL
)
;
COMMIT;
Finished "/home/sayth/workspace/tango_project/manage.py sql rango" execution.

Ah yes I overlooked a warning in the doc.
Warning Whenever you add to existing database models, you will have to
delete the database file and then re-sync the database by running
python manage.py syncb again. This is a drawback of Django 1.5.4, and
can be quite frustrating. If you however add a new model, you can
syncdb your database without having to delete and recreate it. You
must therefore bear this in mind when tweaking your database: new
models will be synchronised with syncdb - but changes to existing
models will not be. When adding a new model to your application’s
models.py file, you can simply run the following command to
synchronise the database with the command $ python manage.py syncdb.
When updating an existing model to your application’s models.py file,
you must perform the following steps. Delete the database. Recreate
the database with the command $ python manage.py syncdb. Populate the
new database with data. Deleting and recreating the database from
scratch is a frustrating process. A possible solution to this issue
could be to use a third party application like South to handle
database schema migrations (changes to your models). South is
currently in active development and is considered a standard solution
for Django schema migrations until this functionality becomes part of
the standard Django codebase. We don’t cover South here - but the
official South documentation provides a handy tutorial if you’re
interested. If you don’t want to use South, we discuss a technique in
Section 5.8 to speed up the updating process. You may have also
noticed that our Category model is currently lacking some fields that
we defined in Rango’s requirements. We will add these in later to
remind you of the updating process.
And it appears migrations in core will not be available until django 1.7.
I had incorrectly updated the populate script it should have looked like.
def add_page(cat, title, url, views=0):
p = Page.objects.get_or_create(category=cat, title=title, url=url, views=views)[0]
return p
def add_cat(name, views=0, likes=0):
c = Category.objects.get_or_create(name=name, views=views, likes=likes)[0]
return c
see
https://stackoverflow.com/a/19759473/461887
django migrations

Related

Is there a way to specify the order of creation of the columns for an SQL table conception using Django?

I'm curently reproducing an old postgresql database with a Django model. The first version of the database had some scripts to compute data to populate the tables.
The data I want to insert in the table are formated as a TSV file : value1\tvalue2\value3. They next will be inserted using the SQL command \copy my_table from 'path/to/my/file.tsv' with null as 'NULL'.
Because the script define the order of the data in the TSV file, my fields have to be created with the same order in the table. The problem is that Django seems to set the Foreign keys to the end of the table.
This model exemple :
class My_table(models.Model):
field1 = models.CharField(primary_key=True, max_length=25)
field2 = models.ForeignKey(....)
field3 = models.IntegerField(blank=True, null=True)
field4 = models.CharField(max_length=2000, blank=True, null=True)
Can give a table like :
field1 | field3 | field4 | field2
--------+--------+--------+--------
I want this :
field1 | field2 | field3 | field4
--------+--------+--------+--------
Is there a way to have this result?
If you're using built-in Django migrations, you can actually re-order the fields defined in a migration file to change the order columns are created in the database.
You should have something similar to this:
# 0001_initial.py
class Migration(migrations.Migration):
....
operations = [
migrations.CreateModel(
# the fields here can be re-ordered
fields=[
('id', ...),
('field1', ....),
('field2', ....),
('field3', ....),
('field4', ....),
]
)
]
You can use python manage.py sqlmigrate appname 0001 to print out the SQL that would be executed:
CREATE TABLE "my_table" ("id", ....);
Note that regardless of field ordering, Django will force "id" to be the first column defined in a table.
I took a look into a Django code and it looks like during make-migration run it first add all normal field followed by one with relations (this way foreign keys field are became last).
So it seems there is no easy solution without modifying Django itself. Thus manual change of 0001_initial.py looks like the only option.
But the manual change of field order is also not a maintainable option for large number of models. So here is a little hack to set order from Models in automatic way.
Add following to the end of your 0001_initial.py file and change db.models to your models:
# import your models
import db.models as my_models
# Change field order to one in model
for op in Migration.operations:
if isinstance(op, migrations.CreateModel):
Model = getattr(my_models, op.name)
fields = {field_tuple[0]: field_tuple for field_tuple in op.fields}
new_fields = []
for field in Model.__dict__:
if field in fields:
new_fields.append(fields[field])
op.fields = new_fields
This code change the order in migrations.CreateModel based on attributes order from original model.
Still not awesome, but at least there is no need to do it manually. Just add a little code at the end.

table items_item has no column named category_id

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).

Setting database with django

I created a db with such tracks.models:
class Song(models.Model):
title = models.CharField(max_length=30)
album = models.ForeignKey(Album)
def __unicode__(self):
return self.title
and used
python manage.py sqall tracks
python manage.py syncdb
but then I changed models to
class Song(models.Model):
songid = models.CharField(max_length=30)
title = models.CharField(max_length=30)
album = models.ForeignKey(Album)
def __unicode__(self):
return self.title
and did
python manage.py sqall tracks
python manage.py syncdb
again. Output of sqall:
BEGIN;
CREATE TABLE "tracks_song" (
"id" integer NOT NULL PRIMARY KEY,
"songid" varchar(30) NOT NULL,
"title" varchar(30) NOT NULL,
"album_id" integer NOT NULL REFERENCES "tracks_album" ("id")
)
;
CREATE INDEX "tracks_song_6781e42a" ON "tracks_song" ("album_id");
COMMIT;
syncdb:
Creating tables ...
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
But whenever I tried to access tracks.models.Song.all() it said:
OperationalError: no such column: tracks_song.songid
So I decided to
python manage.py flush
python manage.py sqall tracks
python manage.py syncdb
(same output)
But problem hasn't gone and there's still no such column: tracks_song.songid.
What's the problem behind it?
python manage.py sqlall app-name will only print SQL sentences, not create or change database structures, that is to say, it's used to check or tell you what django actually do in databases. Howerver, django version<1.7 doesn't track changes of class in models.py(newly increased or delete existed class could be detected and syncdb), but you can use south, or django 1.7 to do such thing.
python manage.py flush will IRREVERSIBLY DESTROY all data, but not change tables in database.
South: http://south.aeracode.org/
Django 1.7: https://docs.djangoproject.com/en/dev/releases/1.7/#django-1-7-release-notes-under-development
you should also notice that if you only need an id field, class Song has a default AutoField id, just use song.id Django models Quick Example

Django testing: DatabaseError: no such table for ManyToManyField

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.

Django - set ForeignKey deferrable foreign key constraint in SQLite3

I seem to be stuck with creating an initialy deferrable foreign key relationship between two models in Django and using SQLite3 as my backend storage.
Consider this simple example. This is what models.py looks like:
from django.db import models
class Investigator(models.Model):
name = models.CharField(max_length=250)
email = models.CharField(max_length=250)
class Project(models.Model):
name = models.CharField(max_length=250)
investigator = models.ForeignKey(Investigator)
And this is what the output from sqlall looks like:
BEGIN;
CREATE TABLE "moo_investigator" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(250) NOT NULL,
"email" varchar(250) NOT NULL
)
;
CREATE TABLE "moo_project" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(250) NOT NULL,
"investigator_id" integer NOT NULL REFERENCES "moo_investigator" ("id")
)
;
CREATE INDEX "moo_project_a7e50be7" ON "moo_project" ("investigator_id");
COMMIT;
"DEFERRABLE INITIALLY DEFERRED" is missing from the *investigator_id* column in the project table. What am I doing wrong?
p.s. I am new to Python and Django - using Python version 2.6.1 Django version 1.4 and SQLite version 3.6.12
This behavior is now the default. See https://github.com/django/django/blob/803840abf7dcb6ac190f021a971f1e3dc8f6792a/django/db/backends/sqlite3/schema.py#L16
Sqlite backend does not add "DEFERRABLE INITIALLY DEFERRED". Check the code

Categories