DRF created_by updated_by fail during migrations - django-models

I want to add an created_by and updated_by field to all my DB objects. I created a common model for this that will be used by most other objects. I have sorted out most obstacles so far. But the make migrations script ends with an error:
My model:
class CommonModel(models.Model):
"""Common fields that are shared among all models."""
created_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_at = models.DateTimeField(auto_now=True,
editable=False)
class Meta:
abstract = True
class Tag(CommonModel):
"""Tag to be used for device type"""
name = models.CharField(max_length=255)
def __str__(self):
return self.name
The error I get is :
You are trying to add a non-nullable field 'created_by' to devicetype without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit, and let me add a default in models.py
The only "solution" I found searching the Internet was to define default='', run the makemigrations again and then manually edit the files afterwards to remove the default=''.
I cannot believe that this is the proper way to do this and that there is no solution for this yet.

You need to set a default value for created_at and update_at, since they are not null=True.
The message you get during migration is not an error. If you want to provide a default value, select fix 1., it should show the below prompt,
Please enter the default value now, as valid Python
The datetime and ` modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>>
Here you can set the default value using the datetime or django.utils.timezone module.

Related

Integrate django model with legacy db

I understand that Django Model is pretty fussy when it comes to the absence of a primary key.
I have a legacy database (SQL Server) that I am connecting too (it is not the default one), and in that I have a database.view which I am supposed access. However, the issue is that the view does not have any primary key.
How do i enable django to query from that table without being able to modify the schema?
Here is what I did:
I created a ReadOnlyModel and got my other django model to subclass it. This was done because I wanted to bypass the django's need for PK (evidently it did work, but threw another error - see below)
class ReadOnlyModel(models.Model):
def save(self, *args, **kwargs):
pass
def delete(self, *args, **kwargs):
pass
I created an ActiveObjectManager for Django to know which database to point too. The reason i used this over a router is because the router would work best if I was creating two seperate applications in the same repo. However, I am using one application:
class Db2ActiveObjectManager(models.Manager):
def get_queryset(self):
qs = super(Db2ActiveObjectManager, self).get_queryset()
if hasattr(self.model, 'use_db'):
qs = qs.using(self.model.use_db)
return qs
Below is a sample model from the Db2:
class modelA(ReadOnlyModel):
use_db = 'db2'
objects = Db2ActiveObjectManager()
col1 = models.CharField(primary_key=True, max_length=256)
col2 = models.CharField(primary_key=True, max_length=1024)
col3 = models.CharField(primary_key=True, max_length=256)
col4 = models.CharField(primary_key=True, max_length=100)
col5 = models.CharField(max_length=256)
col6 = models.CharField(primary_key=True, max_length=50)
class Meta:
managed = False
db_table = 'db2.someTable'
#classmethod
def methodA(cls):
try:
filter_condition = {}
return cls.objects.filter(**filter_condition)
except Exception as e:
raise ValueError("Invalid input")
#classmethod
def methodB(cls):
try:
return cls.objects.raw('SQL Query Here')
# cursor = connection.cursor()
# cursor.execute('SQL Query Here')
# field_names = [field[0].lower() for field in cursor.description]
# nt_result = namedtuple('Result', field_names)
# return [nt_result(*row) for row in cursor.fetchall()]
except Exception as e:
raise
So far my current setup is throwing the following error:
django.db.utils.ProgrammingError: ('42S02', "[42S02] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Invalid object name 'api_readonlymodel'. (208) (SQLExecDirectW)")
I seen many developers on stackoverflow re-iterating that we need to add a pk to the table/view. But i cannot make any changes to that view. I am pretty sure that there is a work around, but no matter what I have tried so far, nothing seems to work out for me yet.
Either I get the above error^ or I get an error saying that no valid column called id is found, or I get an error stating that I need a PK...
Thanks for the help

Peewee : How to update specific fields?

I'm using Peewee for working with database. I have a User tables with 3 fields: username, password and last_login. When a user login to the system i want to update last_login. I've use following lines of code:
from peewee import *
import datetime
class User(Model):
username = CharField(unique=True)
password = CharField()
last_login = DateTimeField(default=datetime.datetime.now())
class Meta:
database = MySQLDatabase('mydb', user='root', charset='123456')
u=User(username="user1", last_login=datetime.datetime.now())
u.save()
Although i haven't specified any value for password, it is overwritten after u.save() is called. How should i force peewee to only update last_login field?
Replace u.save() with:
u.save(only=[User.last_login])
As the API's documentation says:
only (list) – A list of fields to persist – when supplied, only the given fields will be persisted.
So you should specify a list of fields you want to be changed.
You can use the only argument when calling save(). http://docs.peewee-orm.com/en/latest/peewee/api.html#Model.save
When a user login to the system i want to update last_login. I've use following lines of code:
If you want to do this, you should do an atomic update, however:
User.update({User.last_login: datetime.datetime.now()}).where(User.username == 'whatever').execute()
The following code will demonstrate how to create, get and update a record in the database:
now = datetime.datetime.now()
# create a user
u = User.create(username="user1", password="bla", last_login=now)
# now `u` has your user, you can do: print u.username, u.password, u.last_login
# get an existing user from the db
u = User.get(User.username == "user1")
print u.username, u.password, u.last_login
sleep(1)
now = datetime.datetime.now()
# update an existing user
u = User.update(password="blabla", last_login=now).where(User.username == "user1")
u.execute()
If you want to save only modified fields, you may use the method below:
class User(Model):
username = CharField(unique=True)
password = CharField()
last_login = DateTimeField(default=datetime.datetime.now())
class Meta:
database = MySQLDatabase('mydb', user='root', charset='123456')
# This method saves only modefied fields
only_save_dirty = True
u=User(username="user1", last_login=datetime.datetime.now())
u.save()

Getting a 'The data types nvarchar(max) and ntext are incompatible in the equal to operator.'

I am trying to populate a table with data and am using Django's get_or_create method. Whenever I do this it will enter records into the database but at a certain record it will throw the above error. My queryset function is
r, created = Response.objects.get_or_create(
auth_user=auth_user,
name=surv_name,
organization=org_id,
category=category,
question=question,
present_order=present_order,
reference=reference,
quest_id=quest_id,
survey_id=survey_id
)
My response table is
class Response(models.Model):
auth_user = models.ForeignKey('AuthUser')
survey = models.ForeignKey('Survey')
name = models.CharField(max_length=50)
organization = models.ForeignKey('Organization')
tf_question_key = models.CharField(max_length=50)
category = models.CharField(max_length=25, blank=True, null=True)
question = models.CharField(max_length=2048)
quest_id = models.CharField(max_length=25)
present_order = models.IntegerField()
reference = models.CharField(max_length=20)
answer = models.CharField(max_length=2048)
remediation = models.CharField(max_length=2048, blank=True, null=True)
dt_started = models.DateTimeField(db_column='DT_Started',
auto_now_add=True) # Field name made lowercase.
dt_completed = models.DateTimeField(db_column='DT_COMPLETED',
auto_now_add=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'response'
and the traceback where the error is located is
organization <Organization: Individual Offices>
r <Response: Response object>
user_id 2
question ('Does your written policy include the follow-up process for significant outstanding checks, including, but not limited to, checks to recording clerk, checks to tax collector, hazard insurance checks, underwriter checks or checks for mortgage payoffs and any other high risk items? ( 2.03 k )')
present_order 21
survey_id 1
reference '2.03 (k)'
quest_id 27
created True
category 'Pillar II'
surv_name 'Compliance Benchmark'
org_id 1
auth_user <AuthUser: AuthUser object>
I can add records to the table by using
r = Response(
auth_user=auth_user,
name=surv_name,
organization=organization,
category=category,
question=question,
present_order=present_order,
reference=reference,
quest_id=quest_id,
survey_id=survey_id
)
r.save()
but I need to use the get_or_create method to avoid duplicating records. I am not sure why I can add records with the .save() method but not with get_or_create and also why with get_or_create it will add records up to a certain one and then fail. The only thing that is changing is the question, quest_id, present_order, and reference.
I am using python 3.4, django 1.8.4 and SQL Server 2014
Any insight would be greatly appreciated.
I ran into the same issue and turned on logging on sql server to see what was occurring. It looks like long text fields are being converted to ntext. This is then being compared to the nvarchar field causing the error.
The error is occurring during the SELECT within the get_or_create function. Instead of using get_or_create, query for your model with startswith. Using startswith performs a LIKE check which will work. I also added a length check on the field to ensure the fields will match instead of finding other rows with the same starting value.
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.functions import Length
attrs = {
auth_user=auth_user,
name=surv_name,
organization=org_id,
category=category,
present_order=present_order,
reference=reference,
quest_id=quest_id,
survey_id=survey_id,
}
try:
r = Response.objects.annotate(
text_len=Length('question')
).get(
text_len__exact=len(question),
question__startswith=question,
**attrs
)
except ObjectDoesNotExist:
r = Response.objects.create(
question=question,
**attrs
)

How Can I Automatically Populate SQLAlchemy Database Fields? (Flask-SQLAlchemy)

I've got a simple User model, defined like so:
# models.py
from datetime import datetime
from myapp import db
class User(db.Model):
id = db.Column(db.Integer(), primary_key=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
date_updated = db.Column(db.DateTime())
def __init__(self, email, password, date_updated=None):
self.email = email
self.password = password
self.date_updated = datetime.utcnow()
When I create a new User object, my date_updated field gets set to the current time. What I'd like to do is make it so that whenever I save changes to my User object my date_updated field is set to the current time automatically.
I've scoured the documentation, but for the life of me I can't seem to find any references to this. I'm very new to SQLAlchemy, so I really have no prior experience to draw from.
Would love some feedback, thank you.
Just add server_default or default argument to the column fields:
created_on = db.Column(db.DateTime, server_default=db.func.now())
updated_on = db.Column(db.DateTime, server_default=db.func.now(), server_onupdate=db.func.now())
I prefer the {created,updated}_on column names. ;)
SQLAlchemy docs about column insert/update defaults.
[Edit]: Updated code to use server_default arguments in the code.
[Edit 2]: Replaced onupdate with server_onupdate arguments.
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())

GAE change field name/attribute

Is it possiible to change attribute name on db.Model kind? i have some field name created with dash (e.g. field-name) that resulting error.
class DataBulk(db.Model):
group_id = db.IntegerProperty()
group_name = db.StringProperty()
geo_pos = db.GeoPtProperty()
group-leader = db.StringProperty() <-----------error
imported = db.IntegerProperty(default=0)
Anyone can tell me what's wrong?
You must use valid Python names to define properties like that. Strictly speaking you can define the name that is stored in datastore, passing an argument "name" to the property:
class DataBulk(db.Model):
group_id = db.IntegerProperty()
group_leader = db.StringProperty(name='group-leader')

Resources