TimeField question regarding blank/null - django

I have a model (and model form based on it) that has several time fields. I want these fields to be optional such that the user may leave some empty. My problem is that I continue to receive "Column 'mechreturn_tm' cannot be null" errors when I attempt to save an instance where one or more of these fields are blank. I've used the following approaches:
mechreturn_tm = models.TimeField(blank=True, null=False)
mechreturn_tm = models.TimeField(blank=True, null=True)
mechreturn_tm = models.TimeField()
none seem to work. what am I doing wrong?

Are you sure you still get the error using the second approach (both blank and null set to to True)?
Keep in mind that you'll need to recreate the DB table when you make this change since syncdb won't alter an existing table. That may be why you got the error even with the correct code.
Setting blank=True on a model field means that the field is allowed to be blank when validating a form with that field.
Setting null=True means that the model can be saved to the DB without any value at all for that field.
http://docs.djangoproject.com/en/dev/topics/db/models/#field-options

Related

Object not found, but does exist

I have an existing working site, that takes advantage of Adobe Lightroom's catalog being an sqlite3 db. The model is auto-generated.
Whilst updating the code for the site (to TemplateView and streamlining), I thought I'd get adventurous and pull on one of the class models to get the information about how many times a face (person) appears in the photos.
The model:
class Aglibrarykeywordpopularity(models.Model):
id_local = models.IntegerField(primary_key=True, blank=True, null=False)
occurrences = models.TextField() # This field type is a guess.
popularity = models.TextField() # This field type is a guess.
tag = models.TextField(unique=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'AgLibraryKeywordPopularity'
The 'tag' value is obtainable from another model, where it's called 'id_local':
face_id = list(Aglibrarykeyword.objects.values_list('id_local', flat=True))
The values for the 'face_id' are all present in the previous 'tag' field when you view the db.
However, when using:
for a in face_id:
face_pop.append(Aglibrarykeywordpopularity.objects.get(tag=a).occurrences)
.. it complains that there are no matches. I've substituted a for a number, or string of the number, even adding .0 to the representation, and it still complains no matches. I've tried .filter...first() etc.
slides.models.DoesNotExist: Aglibrarykeywordpopularity matching query does not exist
My current work-around is going to output All() of the objects to lists and obtain the values I want that way - which works, but I'm interested more in why it's not working as it should.
Something I notice is that the model has tag defined as TextField, and when I obtain the values myself from All() they are float numbers. Is it the case that there's a sort of 3 way mismatching of variable types, 1)the model 2)the data 3)the query - so no matter if I put a float number or text in my query, it will never match? i.e. do I have to change the model, migrate it and all should be well? (as I'm no Django expert, does the "managed = False" mean that even if I do this, it will not effect the db data?)
TIA for comments.

django.db.utils.OperationalError: cannot ALTER TABLE because it has pending trigger events

I am trying to change accepted_answer ForeignKey to a BooleanField and while migrating getting the error django.db.utils.OperationalError: cannot ALTER TABLE "forum_thread" because it has pending trigger events. This is the models.py of before:
class Thread(models.Model):
title = models.CharField(max_length=300)
answer_count = models.PositiveIntegerField(default=0)
added_at = models.DateTimeField(auto_now_add=True)
accepted_answer = models.ForeignKey('forum.Post', null=True, blank=True, related_name='+')
This error seems to happen when trying to update and change schema of the same table in one operation.
For example, after providing new default values when prompted by makemigrations when removing null=True from a field, this error seems to appear because Django is trying to change nullability while also updating the column.
Workarounds, depending on situation:
Easiest is often adding a new field with the desired properties, then removing the old field (maybe after copying data over).
If the error can be avoided by setting values for all fields that were needing a new default value (Django asking during the migration), try setting those values before making the migration/schema change.
In your specific case, adding a new field then removing the old is probably the way to go.
Adding to Max Lemieux's answer, if you try to change a field from nullable to non-nullable, this is impossible in the same database transaction, thus:
you can split your operations into 2 migrations (not recommended if complex operations)
you can wrap your migration's operations with these two statements to force PostgreSQL to check null constraint on save and not at the end of transaction
operations = [
migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE', reverse_sql='SET CONSTRAINTS ALL DEFERRED'),
... # your other operations here
migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED', reverse_sql='SET CONSTRAINTS ALL IMMEDIATE'),
]

Django Auto UUID in Model not unique

Not sure if this is a bug in Django, or it just doesn't support what I'm trying to do (or how i'm doing it).
A snippet of my model:
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True, related_name='profile'
login_hash = models.CharField(max_length=36, blank=True, null=True, default=uuid.uuid4())
...
As you see, i've set the default for login_hash to a call to uuid.uuid4()
works fine... however, multiple calls to the UserProfile (creating new users quickly, even seemingly a few minutes, but i've not an official time) will result in the same login_hash for multiple users.
It appears that django (i'm on 1.7.4) is caching the result of uuid4() for some period of time. not good for what i'm trying to do.
SOLUTION:
that i'm using. I've simply set an 'on insert' trigger on the database, so that when i insert a new record, the database generates the UUID, but only on inserts/new records.
Is there a way to do it within django so that i can keep it database agnostic?
works fine... however, multiple calls to the UserProfile (creating new users quickly, even seemingly a few minutes, but i've not an official time) will result in the same login_hash for multiple users.
As the code is currently written you're calling uuid.uuid4() at the point UserProfile is imported. It'll be called once and the resulting value will be the default for all new creations.
What you instead what to do is pass a callable as the default. Like so: default=uuid.uuid4.
Also, for CharField I'd strongly suggest not allowing NULL values as well as blank values. It's also not clear if you really do want to allow blank values for this field, but let's assume that you do. You should end up with this:
login_hash = models.CharField(max_length=36, blank=True, default=uuid.uuid4)

django does django have an automatic timestamp create/update field like cakephp?

having used cakephp in the past, one thing (perhaps the only thing?) i liked about it was that it had a "create" and "update" timestamp capability that was lovely - simply put, when you first added an item, the "create" date was set (assuming you named it right - create_date, i think)
Anytime thereafter, if an update was performed, the "update" field was set to the current time.
Does django have this as well? If so, what/how do i name the fields to get it to pick them up?
It is not added to your model built-in in every table. You must add it as field to your model.
class Message(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Message in this case your table's name.
Sure it has!
Check auto_now and auto_now_add in the doc

Creating Custom User Backends in Django

I have a Shops model and would like each shop to be able to login to my application. Following as best I can the guide at http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/ and various other googlings, I've got part of the way there, but I've run into a problem. When I try to login as a shop, I get the following error:
OperationalError at /login/
(1054, "Unknown column 'shops.user_ptr_id' in 'field list'")
Shops model:
class Shops(User):
shop_id = models.AutoField(primary_key=True)
shop_code = models.CharField(unique=True, max_length=5)
shop_type_fk = models.ForeignKey(ShopTypes,
null=True,
db_column='shop_type_id',
blank=True)
address_fk = models.ForeignKey(Addresses, db_column='address_id')
phone_number = models.CharField(max_length=30)
#email = models.EmailField(max_length=255, blank=True)
description = models.TextField(blank=True)
does_gift_aid = models.NullBooleanField(null=True, blank=True)
objects = UserManager()
class Meta:
db_table = u'shops'
I've sync'd the database, so surely it should have made the column user_ptr_id. Does anyone know where I'm going wrong?
"I've sync'd the database, so surely it should have made the column user_ptr_id."
What makes you think that? Especially in light of this clear statement in the docs for syncdb:
Syncdb will not alter existing tables
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.
Changes to model classes and database
schemas often involve some form of
ambiguity and, in those cases, Django
would have to guess at the correct
changes to make. There is a risk that
critical data would be lost in the
process.
If you have made changes to a model
and wish to alter the database tables
to match, use the sql command to
display the new SQL structure and
compare that to your existing table
schema to work out the changes.
It does sound like you had an existing shops table before changing it to inherit from User (as Daniel notes), and syncdb does not update the schema for existing tables.
You need to drop the table and then run syncdb, if possible. Otherwise you need to go into your database and add the user_ptr_id field manually, if you know how to do that. The definition should look something like this:
"user_ptr_id" integer NOT NULL UNIQUE REFERENCES "auth_user" ("id")