changing django default model settings - python

I'm just starting with the django creating your own app tutorial (creating a Poll) I'm deviating slightly as I'm wanting to create an app using my own database model that already exists.
And in the tutorial it says
Table names are automatically
generated by combining the name of
the app (polls) and the lowercase
name of the model -- poll and choice.
(You can override this behavior.)
Primary keys (IDs) are added
automatically. (You can override
this, too.)
By convention, Django appends
"_id" to the foreign key field
name. Yes, you can override this,
as well.
But I can't see where it mentions how you can override this behaviour? I've defined my model as so
from django.db import models
# Create your models here.
class Channels(models.Model):
channelid = models.IntegerField()
channelid.primary_key = True
channelname = models.CharField(max_length=50)
Now when I go in to the shell this is what I get
>>> from tvlistings.models import *
>>> Channels.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Python26\lib\site-packages\django\db\models\query.py", line 67, in __
repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "C:\Python26\lib\site-packages\django\db\models\query.py", line 82, in __
len__
self._result_cache.extend(list(self._iter))
File "C:\Python26\lib\site-packages\django\db\models\query.py", line 271, in i
terator
for row in compiler.results_iter():
File "C:\Python26\lib\site-packages\django\db\models\sql\compiler.py", line 67
7, in results_iter
for rows in self.execute_sql(MULTI):
File "C:\Python26\lib\site-packages\django\db\models\sql\compiler.py", line 73
2, in execute_sql
cursor.execute(sql, params)
File "C:\Python26\lib\site-packages\django\db\backends\util.py", line 15, in e
xecute
return self.cursor.execute(sql, params)
File "C:\Python26\lib\site-packages\django\db\backends\mysql\base.py", line 86
, in execute
return self.cursor.execute(query, args)
File "C:\Python26\lib\site-packages\MySQLdb\cursors.py", line 166, in execute
self.errorhandler(self, exc, value)
File "C:\Python26\lib\site-packages\MySQLdb\connections.py", line 35, in defau
lterrorhandler
raise errorclass, errorvalue
DatabaseError: (1146, "Table 'tvlistings.tvlistings_channels' doesn't exist")
Obviously it can't find the table tvlistings_channels as it's actually called channels. So how do I change the default?

You can override Model behavior in Django largely through the use of an inner Meta class
db_table allows you to rename the table name
specifying another field as the primary key will have it use that rather than a surrogate key (not in the Meta class, just in the model itself)

You should try and work your way all through the tutorial before you try and customise things. All these things are covered in the actual documentation, but it's best to have a basic understanding of things first before diving into that.
FWIW, here are the docs on defining your own primary key and specifying a table name. But really, do the tutorial as written first.

Related

Using a model's sub-classes as choice options for that model raises NameError

We are trying to upgrade a legacy code's django version from 1.8 to 1.9. We have one model that is defined like this:
def _get_descendant_question_classes():
stack = [Question]
while stack:
cls = stack.pop()
stack.extend(cls.__subclasses__())
yield cls
def _get_question_choices():
question_classes = _get_descendant_question_classes()
for cls in question_classes:
yield (cls.slug, cls._meta.verbose_name)
class Question(models.Model):
slug = "Question"
type = models.CharField(max_length=10, choices=_get_question_choices(), default=slug)
class TextQuestion(Question):
slug = "TextQuestion"
class SelectQuestion(Question):
slug = "SelectQuestion"
...
Basically the model wants to use its sub-classes as choice options for one of its fields. It does this with traversing the model in a DFS manner and yielding all the sub-classes.
This code works in django 1.8 but in django 1.9 it gives this error:
Traceback (most recent call last):
File "./manage.py", line 16, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 350, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 324, in execute
django.setup()
File "/usr/local/lib/python2.7/site-packages/django/__init__.py", line 18, in setup
apps.populate(settings.INSTALLED_APPS)
File "/usr/local/lib/python2.7/site-packages/django/apps/registry.py", line 108, in populate
app_config.import_models(all_models)
File "/usr/local/lib/python2.7/site-packages/django/apps/config.py", line 202, in import_models
self.models_module = import_module(models_module_name)
File "/usr/local/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
File "/home/saeed/saeed/survey/models.py", line 85, in <module>
class Question(models.Model):
File "/home/saeed/saeed/survey/models.py", line 99, in Question
type = models.CharField(max_length=10, choices=_get_question_choices(), default=slug)
File "/usr/local/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1072, in __init__
super(CharField, self).__init__(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 161, in __init__
choices = list(choices)
File "/home/saeed/saeed/survey/models.py", line 65, in _get_question_choices
for cls in question_classes:
File "/home/saeed/saeed/survey/models.py", line 54, in _get_descendant_question_classes
stack = [Question]
NameError: global name 'Question' is not defined
I understand the problem what I don't understand is how this works in django 1.8? What has changed in django 1.9 that causes this? What is the best way to fix this?
I can reproduce this; with Django 1.8, python3 -m manage check succeeds, while in Django 1.9 it raises a NameError.
There is nothing particular in the Django 1.9 release notes that addresses this change in behaviour.
I would explain this Django 1.8 behaviour by noting that Django is notorious for doing “magic” on the code in order to allow referencing not-yet-executed parts of the code to define models. It is an anomaly from normal Python behaviour, and AFAICT an undocumented one.
So this would be a behaviour that was only accidental and undocumented (therefore should not be relied on), where in normal Python you would expect a NameError when referencing Question before it is defined.
Django 1.9 evidently made a change that reverts to the expected Python behaviour :-)
The exception is due to, when the method _get_descendant_question_classes is defined, the class Question is not defined yet. So, you are referring something that doesn't exist.
You have a design issue here, note you have a cyclic dependency: _get_descendant_question_classes depend on Question and Question depend on _get_descendant_question_classes.
A quick fix could be to use get_model:
def _get_descendant_question_classes():
stack = [get_model('yourappnamehere', 'Question')]
I'm not sure why you need that type field, but I'm confident that you can solve your original problem (what lead you to add that type field) in another simpler way.
Also, in case you need to know the "type" of a Question instance, you just need to check if the object has the attr textquestion_ptr or selectquestion_ptr or just use isinstance
The problem is that, when the class variable typeis initialized in the Question class, the Question class hasn't been created, and yet _get_question_choices(), which references the Question class, gets evaluated right away in order to assign a value to the type's choices, resulting in a circular reference.
To avoid this issue, instead of evaluating _get_question_choices() right away during class declaration, you can initialize type with empty choices first, and then give it the preferred value in Question's __init__ method, which is called only after Question has been instantiated:
class Question(models.Model):
type = models.CharField(max_length=10, choices=(,), default=slug)
def __init__(self, *args, **kwargs):
super(Question, self).__init__(*args, **kwargs)
self._meta.get_field('type').choices = _get_question_choices()

django ValueError when loading JSON fixture with many-to-many relationships

I am building a website with django/python. The website database I am building contains books, and I am trying to relate Character objects to Event objects by defining their relationships in the fixture. I load my fixtures from .json files using
loaddata fixtures <file>
This works for my models that have no relationships, but when I try to load a fixture that contains many-to-many relationships (characters appear in many events, events contain many characters) I get the following :
ValueError: Problem installing fixture: < file path >: "< Character: Lanoree Brock > " needs to have a value for field "character" before this many-to-many relationship can be used.
There is no field "character" in my model for Character:
class Character(models.Model):
id = models.IntegerField(primary_key = True)
name = models.CharField(max_length = ml)
bio = models.TextField()
event = models.ManyToManyField(Event)
def __str__(self):
return self.name
class Meta:
ordering = ('name',)
The .json file for my Character fixture looks like this:
[{"model": "library.Character", "id": 1,
"fields": {"name": "Lanoree Brock", "bio": "He lived", "event": [101, 102, ...]}}
... ]
So the error occurs at the first Character. My guess as to the problem is that django tries to add the relationship to the < Character: Lanoree Brock > object before it saves the object, but I do not understand why it is doing that or how to get around it.
Is there a way to structure the fixture to ensure that when it is loaded each object is created/saved before the code tries to define its relationships?
I am new to django, JSON syntax, and web dev in general, and I feel like there's something simple I'm not doing here -- if fixtures cannot handle many-to-many relationships, that seems like a huge oversight in their functionality.
Any help would be appreciated, thank you!
Edit: The full error log:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\__init__.py", line 353, in execute_from_command_line
utility.execute()
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\__init__.py", line 345, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\base.py", line 348, in run_from_argv
self.execute(*args, **cmd_options)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\base.py", line 399, in execute
output = self.handle(*args, **options)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\commands\loaddata.py", line 60, in handle
self.loaddata(fixture_labels)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\commands\loaddata.py", line 100, in loaddata
self.load_label(fixture_label)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\managemen
t\commands\loaddata.py", line 158, in load_label
obj.save(using=self.using)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\core\serialize
rs\base.py", line 204, in save
setattr(self.object, accessor_name, object_list)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\db\models\fiel
ds\related_descriptors.py", line 480, in __set__
manager = self.__get__(instance)
File "c:\Users\MetalGearSamus\Anaconda\lib\site-packages\django\db\models\fiel
ds\related_descriptors.py", line 468, in __get__
return self.related_manager_cls(instance)
File "c:Users\MetalGearSamus\Anaconda\lib\site-packages\django\db\models\fiel
ds\related_descriptors.py", line 751, in __init__
(instance, self.source_field_name))
ValueError: Problem installing fixture 'c:Users\MetalGearSamus\Personal\Legends\website\library\fixtures\database.json': "<Character: Lanoree Brock>" needs to
have a value for field "character" before this many-to-many relationship can be
used.

FieldError: Invalid field name(s) given in select_related: 'userinfo'. Choices are: userinfo

I get this error when trying to use only with select_related.
FieldError: Invalid field name(s) given in select_related: 'userinfo'. Choices are: userinfo
It's a little strange that it reports the field I'm trying to select as an error. Here is my query:
users_with_schools = User.objects.select_related('userinfo').only(
"id",
"date_joined",
"userinfo__last_coordinates_id",
"userinfo__school_id"
).filter(
userinfo__school_id__isnull=False,
date_joined__gte=start_date
)
I've been able to use select_related with only in other places in my code so I am not sure why this is happening.
Edit: Here is the full traceback
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "env/lib/python2.7/site-packages/django/db/models/query.py", line 138, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "env/lib/python2.7/site-packages/django/db/models/query.py", line 162, in __iter__
self._fetch_all()
File "env/lib/python2.7/site-packages/django/db/models/query.py", line 965, in _fetch_all
self._result_cache = list(self.iterator())
File "env/lib/python2.7/site-packages/django/db/models/query.py", line 238, in iterator
results = compiler.execute_sql()
File "env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 818, in execute_sql
sql, params = self.as_sql()
File "env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 367, in as_sql
extra_select, order_by, group_by = self.pre_sql_setup()
File "env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 48, in pre_sql_setup
self.setup_query()
File "env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 39, in setup_query
self.select, self.klass_info, self.annotation_col_map = self.get_select()
File "env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 203, in get_select
related_klass_infos = self.get_related_selections(select)
File "env/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 743, in get_related_selections
', '.join(_get_field_choices()) or '(none)',
FieldError: Invalid field name(s) given in select_related: 'userinfo'. Choices are: userinfo
From the documentation:
All of the cautions in the note for the defer() documentation apply to only() as well. Use it cautiously and only after exhausting your other options.
...
Using only() and omitting a field requested using select_related() is an error as well.
select_related will try to fetch all the columns for userinfo. As described above, trying to restrict the set of columns to specific ones will result in an error - the combination of select_related and only does not support that.
It's probably worth noting the comment that goes with these methods:
The defer() method (and its cousin, only(), below) are only for advanced use-cases. They provide an optimization for when you have analyzed your queries closely and understand exactly what information you need and have measured that the difference between returning the fields you need and the full set of fields for the model will be significant.
Edit: you mention in a comment below that the following query, used elsewhere in your code, seems to work fine:
ChatUser.objects.select_related("user__userinfo").\
only( "id", "chat_id", "user__id", "user__username", "user__userinfo__id" )
My best guess is that you are hitting this bug in Django (fixed in 1.10).
I suppose the easiest way to verify is to check the SQL query generated by the queryset that seems to work. My guess is that you will find that it isn't actually querying everything in one go and that there are additional queries when you try to access the related model that you asked to be fetched in select_related.

DatabaseError: column does not exist

I added New Column FK_Project in the rw_item Table, which is reference of the Project_Master table.
dp=# ALTER TABLE digital_publisher_rw_item ADD FK_Project int;
ALTER TABLE
dp=# ALTER TABLE digital_publisher_rw_item ADD FOREIGN KEY(FK_Project) REFERENCES digital_publisher_project_master(id);
ALTER TABLE
Now I am writing script to add values of to Column FK_Project in the rw_item Table.
But getting following exception,
Exception:
>>> rw_item
<class 'dp.digital_publisher.models.rw_item'>
>>> rw_item.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 67, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 82, in __len__
self._result_cache.extend(self._iter)
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 271, in iterator
for row in compiler.results_iter():
File "/usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 677, in results_iter
for rows in self.execute_sql(MULTI):
File "/usr/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 732, in execute_sql
cursor.execute(sql, params)
File "/usr/lib/python2.6/site-packages/django/db/backends/util.py", line 15, in execute
return self.cursor.execute(sql, params)
File "/usr/lib/python2.6/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 44, in execute
return self.cursor.execute(query, args)
DatabaseError: column digital_publisher_rw_item.FK_Project_id does not exist
LINE 1: ..."digital_publisher_rw_item"."deletion_date_time", "digital_p...
^
Django models.py:
FK_Project = models.ForeignKey(Project_Master, null=True, blank=True)
How to handle this?
Since you are adding fields manually, instead of using Django's database migrations, as noted by Shang Wang, you just need to make sure that the field names match up. In this case, take note of the exact error given by Django:
DatabaseError: column digital_publisher_rw_item.FK_Project_id does not exist
It is looking for FK_Project_id, as opposed to the FK_Project, which you added. This is because of a convention in Django, which appends _id to the end of ForeignKey columns. So, you have two options for handling this:
Rename the column in the database: ALTER TABLE digital_publisher_rw_item RENAME COLUMN FK_Project TO FK_Project_id
Tell Django to use the column you created: FK_Project = models.ForeignKey(Project_Master, null=True, blank=True, db_column='FK_Project')

Django syncdb works in SQLite, failing in MySQL

I'm a newbie to MySQL, and haven't used Django for anything in production. I've been doing development under Windows 7 with SQLite, and am trying to move the code to a Linux server running MySQL.
When I ran syncdb, it created the first three tables then threw an error:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
utility.execute()
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/core/management/__init__.py", line 392, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/core/management/base.py", line 242, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/core/management/base.py", line 285, in execute
output = self.handle(*args, **options)
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/core/management/base.py", line 415, in handle
return self.handle_noargs(**options)
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/core/management/commands/syncdb.py", line 96, in handle_noargs
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
File "/home/gsdemo01/project_file/lib/python3.3/site-packages/django/db/backends/creation.py", line 83, in sql_create_model
model, f, known_models, style)
TypeError: sql_for_inline_foreign_key_references() takes 4 positional arguments but 5 were given
The model immediately after the last one created is a Metaclass, followed by a class that inherits from it:
class Location(models.Model):
# con = models.ForeignKey(Convention)
name = models.CharField(max_length=40)
scheduler = models.ForeignKey(GCUser, blank=True, null=True)
class Meta:
abstract = True
def __str__(self):
return self.name
class Room(Location):
tag = models.CharField(max_length=10)
capacity = models.PositiveSmallIntegerField(default=100)
This works fine with SQLite, so it seems like it has to be either a problem with the python connector package or with MySQL itself.
Thanks in advance for any help.
Update:
Through trial and error I've determined that the issue is definitely with the Foreign Key field. If I comment that out the table is created correctly. As far as I can tell the modification suggested by Yogesh matches what we already have in the code, so if anyone has any other suggestions I'd love to hear them.
If you using these virsions Python3.3 Django1.6 use MySql official middleware mysql-connector-python-1.1.4-py3.3.
The solution:
find: creation.py within your site-packages and Modification method: sql_for_inline_foreign_key_references is: you can only modify the method parameters
def sql_for_inline_foreign_key_references (self, model, field, known_models, style):
This is not a good solution,this is alternate for remove error.
I'm posting the solution here for the benefit of future users who run into this. It took many hours on the part of my partner to ferret this out.
The simple part of the solution is to edit creation.py to change
def sql_for_inline_foreign_key_references (self, model, field, known_models, style):
to
def sql_for_inline_foreign_key_references (self, *args):
There's a routine with the same name and almost the same syntax in site-packages/django/db/backends/creation.py, but you want the one in site-packages/django/db/backends/mysql/creation.py.
You're not done yet, though, because the module gets copied to site-packages/mysql/connector/django/creation.py, and that doesn't happen automatically on edit, so you'll need to copy it over manually. I deleted the .pyc file for good measure, but that "shouldn't" have been necessary.
Of course, none of this should have been necessary...
For Mac users using MacOSX 10.9 (aka Mavericks) or up, this solution works perfectly, but be sure you're going to the right place if you're using python3 to edit the creation.py file from the mysql.connector:
/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/mysql/connector/django/creation.py
FYI:
Environment: Python3 / Mysql-connector-1.1.4 / Django-1.6.1

Categories

Resources