I am trying to create a queryset for getting the values of a DateTimeField which is DATETIME in the DB.
The class in models.py:
class ChangeMetrics(models.Model):
id = models.IntegerField(primary_key=True)
file_id = models.ForeignKey(File, db_column = 'file_id')
version_id = models.ForeignKey(Version, db_column = 'version_id')
function_id = models.ForeignKey(Function, blank=True, db_column = 'function_id')
date = models.DateTimeField(blank=True, null=True)
user = models.TextField(blank=True)
changed = models.IntegerField(blank=True, null=True)
The field in the DB:
date DATETIME
The tuples are populated in the database and running SQL queries directly on the DB is working perfectly.
This is the queryset I am currently using in Django:
queryset = ChangeMetrics.objects.filter(~Q(changed=None), ~Q(date=None), ~Q(version_id=None))
I have tried a raw query and also a version of the query that uses exclude(), but that still returns None for date.
I am accessing the entries in the queryset through a for loop and simply accessing date through entry.date inside the for loop.
Edit:
Django version 1.6.5
I have also tried getting the values through the Django shell, to no success.
Any ideas on what could be wrong?
not sure if you were able to figure this out, but I just had this problem and was able to fix it.
So, Django migrations were creating the column in the DB as datetime(6) instead of datetime. This was causing the Django models to fail to instantiate the Datetime object.
ALTER TABLE `my_table`
MODIFY COLUMN `created` datetime NOT NULL
After running that if fixed my issue. Maybe in your case you could try modifying to datetime(6) instead.
We had this same issue popup while pushing code from local environment (Mac OS X) up to App Engine. While altering the fields like Alexander mentioned to be DATETIME instead of DATETIME(6) did start making them appear, we lost the microseconds. Ended up realizing that in local environment we were running MySQLdb 1.2.5 but when deploying to App Engine, even though we had specified "latest" as the version of MySQLdb, it was only pulling 1.2.4b4, hard-coding to 1.2.5 fixed the issue.
Can you please try this solution:
queryset = list(ChangeMetrics.objects.filter(changed__isnull=False, date__isnull=False, version_id__isnull=False))
EDIT : Try to move the databse out of your folder, then run python manage.py syncdb and check if your database is created correctly according to the Models.
Doesn't work :
Maybe you can try with this (I don't know if it works, I can't try it now) :
queryset = ChangeMetrics.objects.filter(changed!=None, date!=None, version_id!=None)
This issue is caused by an outdated version of MySQL-python not by Django or migrations system.
Using mysqlclient (which is an updated fork of MySQL-python) solves this problem.
I guess you generate (django migrate command) your database schema on mac. Try to delete the schema and re-migrate from a windows machine.
Related
I am running Django on Heroku with zero-downtime feature. This means that during deployment there are two version of code running (old and new) on the same database. That's why we need to avoid any backward incompatible migrations.
It there a possibility to exclude a field from Django query on a given model?
Let say we have a model (version 1):
class Person(models.Model):
name = models.CharField()
address = models.TextField()
In some time in the future we want to move address to the separate table. We know that we should not delete a field for older code to work so Person model may look like (version 2):
class Person(models.Model):
name = models.CharField()
address = models.ForeignKey(Address)
_address = models.TextField(db_name='address')
This way if old code will query for address it will get it from Person table even if database has been migrated (it will be an old value, but let assume thats not a big issue).
How now I can safetly delete _address field? If we will deploy version 3 with _address field deleted then code for version 2 will still try to fetch _address on select, even if it's not used anywhere and will fail with "No such column" exception.
Is there a way to prevent this and mark some field as "non-fetchable" within the code for version 2? So version 2 will not delete field, but will not fetch it anymore and version 3 will delete field.
You can use custom object manager for defer your specific field/fields for all the queryset.
class CustomManager(models.Manager):
def get_queryset(self):
return super(CustomManager, self).get_queryset().defer('_address',)
class Person(models.Model):
name = models.CharField()
address = models.ForeignKey(Address)
_address = models.TextField(db_name='address')
objects = CustomManager()
after that in your any queryset against Person model will not include _address field in query by default.
Yes, you can do it:
QuerySet.defer():
"In some complex data-modeling situations, your models might contain a lot of fields, some of which could contain a lot of data (for example, text fields), or require expensive processing to convert them to Python objects. If you are using the results of a queryset in some situation where you don’t know if you need those particular fields when you initially fetch the data, you can tell Django not to retrieve them from the database." - docs
Entry.objects.defer("headline", "body")
OR
With django 1.8 onwards: use values_list. You can only include fields that you want. You can also use Queryset.only() and Queryset.defer() to refine your queryset queries. You can chain defer() calls as well
Entry.objects.values_list('id', 'headline')
I have a CharField on a Django (1.9) model:
alias = models.CharField(max_length=50)
The app is being used and already has data, and there are objects using all 50 characters already. What is the simplest method to reduce the max_length of this field without getting complaints from my production database when I try to migrate? DB is postgresql if it makes a difference.
I think the right way would be simply go the development python terminal and access all the objects of that particular model and truncate the values for alias as:
for object in MyModel.objects.all():
object.alias = object.alias[:REDUCED_LENGTH]
object.save()
and, the change the max_length in the CharField in your model and run migrations.
to reduce max_length=50 to other max_length=20
> python manage.py makemigrations
> python manage.py migrate
all new data that you save will work with new max_length
for exists data you can make simple script
from myproject.models import Mymodel
for obj in Mymodel.objects.all():
obj.Firstname = obj.Firstname[0:3]
obj.save()
I changed the register logic where now new users have to give their first and second names also. But old users in db don't have those fields filled up, they are empty.
I am wondering now how to set them manually with python manage.py shell, I am using sqlite3, so there is no UI for the db.
is there any solution for it?
the one which came to my mind is to write a update-page for users where they can update their personal info. but then I would need to tell every one of them to do this.
Firstly, I don't know what you mean by "there is no UI for the db" - sqlite has a shell just like any other database, you can go in and write direct SQL update statements.
Secondly, setting fields in the Django shell is just the same as in a view: you import your models, query the instances you want, update the fields, and save the model.
from myapp.models import MyModel
my_instance = MyModel.objects.get(id=whatever)
my_instance.first_name = 'foo'
my_instance.last_name = 'bar'
my_instance.save()
If you are using south, you can do a data migration which is like a schema migration, but deals with data.
You would create a migration, and then add the appropriate code to the forwards method. This way when this migration is applied, data is added for those users that do not have a first and last name.
The other option you have is to do this manually, from the django shell:
>>> from django.contrib.auth import get_user_model
>>> model = get_user_model()
>>> no_names = model.objects.filter(first_name='', last_name='')
>>> no_names.update(first_name='First Name', last_name='Last Name')
I've been having a nightmare of a time trying to get MongoDB working with Django. I now have it successfully installed, but it errors upon the first attempt to save an object. I've been following this tutorial, and the Post model they present I have copied precisely.
Here is the code for the model:
from django.db import models
from djangotoolbox.fields import ListField
class Post(models.Model):
title = models.CharField(max_length=200)
text = models.TextField()
tags = ListField()
comments = ListField()
The post is actually created (and inserted) here:
post = Post.objects.create(
... title='Hello MongoDB!',
... text='Just wanted to drop a note from Django. Cya!',
... tags=['mongodb', 'django'],
... comments=['comment 1', 'comment 2']
... )
The full stack trace can be found here. The error itself is:
InvalidDocument: documents must have only string keys, key was <django.db.models.fields.CharField object at 0x22cae50>
Clearly MongoDB is functioning, because it wants the keys to be strings instead of integers. But why is the rum gone? Err, why are standard Django objects not able to save into the MongoDB database?
I have added the required CharField parameter max_length that was overlooked. It does not work in this case, nor does it if I also remove the lists.
I got this error until updating the django-mongodb-engine library to the current version in the 'develop' branch of the github repository. Simply using the instructions on the article shown will import the master branch.
I have also followed this tutorial and had same error. I managed to fix this problem.
What I did wrong is I used djangotoolbox from github (https://github.com/django-nonrel/djangotoolbox) repository, which was ver 0.9.2. Then I removed this and did it as tutorial states and used bitbucket (https://bitbucket.org/wkornewald/djangotoolbox) that is on ver 0.9.1 of djangotoolbox. Now it works fine.
Does this work:
post = Post(
... title='Hello MongoDB!',
... text='Just wanted to drop a note from Django. Cya!',
... tags=['mongodb', 'django'],
... comments=['comment 1', 'comment 2']
... )
Another thing to try:
class Post(models.Model):
title = models.CharField(primary_key=True, max_length=200)
I think by default Django uses auto-generated numeric values as primary keys. This would force your title to be your primary key... it's a char string, so it might solve the problem you're seeing. It's just a guess, because the actual error your seeing doesn't make too much sense to me.
From what I see, your model looks just fine. The error is funny; it is saying that the key to the attribute you are calling as "title" cannot be anything other than a string, but if I'm not mistaken, the string here is the key "title" and the value is the CharField() field, together representing a key/value pair in the Post document in your MongoDB. Try isolating the problem by jumping into the django shell:
python manage.py shell
and building your Post object from scratch. Use the model that dragonx has mentioned. Simple is best to debug these problems. If you are getting the same error when you try either to call Post.objects.create(p) for a Post object p, or when you call p.save(), try re-writing the Post model and give it another shot.
Finally, you can show us your settings.py file and see what your mongodb settings are there. If you say you are using django-nonrel, then there are basic checks you can make to ensure that python, django, and mongodb are talking to each other.
Let us know how you're doing.
I'm working on what I think is a pretty standard django site, but am having trouble getting my admin section to display the proper fields.
Here's my models.py:
class Tech(models.Model):
name = models.CharField(max_length = 30)
class Project(models.Model):
title = models.CharField(max_length = 50)
techs = models.ManyToManyField(Tech)
In other words, a Project can have different Tech objects and different tech objects can belong to different Projects (Project X was created with Python and Django, Project Y was C# and SQL Server)
However, the admin site doesn't display any UI for the Tech objects. Here's my admin.py:
class TechInline(admin.TabularInline):
model = Tech
extra = 5
class ProjectAdmin(admin.ModelAdmin):
fields = ['title']
inlines = []
list_display = ('title')
admin.site.register(Project, ProjectAdmin)
I've tried adding the TechInline class to the inlines list, but that causes a
<class 'home.projects.models.Tech'> has no ForeignKey to <class 'home.projects.models.Project'>
Error. Also tried adding techs to the fields list, but that gives a
no such table: projects_project_techs
Error. I verified, and there is no projects_project_techs table, but there is a projects_tech one. Did something perhaps get screwed up in my syncdb?
I am using Sqlite as my database if that helps.
I've tried adding the TechInline class to the inlines list, but that causes a
'TechInLine' not defined
Is that a straight copy-paste? It looks like you just made a typo -- try TechInline instead of TechInLine.
If your syncdb didn't create the proper table, you can do it manually. Execute this command:
python manage.py sqlreset <myapp>
And look for the definition for the projects_project_techs table. Copy and paste it into the client for your database.
Assuming your app is called "projects", the default name for your techs table will be projects_tech and the projects table will be projects_project.
The many-to-many table should be something like projects_project_techs
#John Millikin - Thanks for the sqlreset tip, that put me on the right path. The sqlreset generated code that showed me that the projects_project_techs was never actually created. I ended up just deleting my deb.db database and regenerating it. techs then showed up as it should.
And just as a sidenote, I had to do an admin.site.register(Tech) to be able to create new instances of the class from the Project page too.
I'll probably post another question to see if there is a better way to implement model changes (since I'm pretty sure that is what caused my problem) without wiping the database.