I have a django model like below:
from jsonfield import JSONField
class SCUser(User):
address = JSONField(blank=True,null=True)
When I save a json in this address it gets saved as string.
Here is a code snippet:
appuser.address = {"state":""}
appuser.save()
Now if I try to retrieve appuser.address it gives me
>>>appuser.address
>>>u'{"state":""}'
>>>appuser.save()
>>>appuser.address
>>>u'"{\\"state\\":\\"\\"}"'
And it gets recursive.
What am I missing here?
Edit:
The AppUser inherits from SCUser model.
I met this problem when I am using a non-Autofield key as the model's primary key and I found some issues which is still open on github related to this problem.
https://github.com/dmkoch/django-jsonfield/issues/92
https://github.com/dmkoch/django-jsonfield/issues/101
I solved this problem by define a pk property in the model. I don't known is there any side effects by using this solution.
class SCUser(User):
....
#property
def pk(self):
return self.id # your pk
Please try:
appuser.address = {"state":""}
appuser.save()
appuser.get_data_json()
Related
I'm getting a problem working with django and its model system. I'm new working with django and I'm stuck since I've probably making the things wrong.
I'm trying to make an update to my DB and I get this error:
"'dict' object has no attribute 'save'"
I'm only trying to set a field to be active or inactive depending on a check input on my html.
I'm sending the right value on the request.
I'm getting a dictionary instead of a model object, but I don't really know how to change this, I think I followed the django docs. step by step.
models.py:
from django.db import models
class Flags(models.Model):
num = models.IntegerField(null=False)
deliver= models.CharField(max_length=1, null=False)
class Meta:
db_table ="FLAGS"
views.py:
from django.http import HttpResponse
from Logistic.models import Flags
def updateDisponibilidad(request):
flag = request.GET.get("flag")
print(flag)
disp = Flags.objects.using('default').values('num', 'deliver').get(num__exact=1)
print(disp)
disp['deliver'] = str(flag)
disp.save()
return HttpResponse(disponibilidad)
Django docs. says I can acces to the values putting (in this case) disp.deliver, but when I do that, i get a different error:
'dict' object has no attribute 'deliver'
It would be fantastic if anyone can help me so I be able to use this code:
disp.deliver = flag
disp.save()
And work with that.
This is due to the .values() in your query, if you want to obtain a Flags object, you should remove that, so:
def updateDisponibilidad(request):
flag = request.GET.get("flag")
disp = Flags.objects.using('default').get(num=1) # no .values()
print(disp)
disp['deliver'] = str(flag)
disp.save()
return HttpResponse(disponibilidad)
If you use .values(), you retrieve a dictionary. Here we retrieve a Flags object, and model objects have a .save() method to update the object in the database.
If you want to render the content to a JSON response, you should use a serializer, not use Django ORM features for that.
Furthermore if you update entities, one typically uses a POST, PUT, PATCH, etc. request, not a GET request.
I have two models that look like this:
class ModelOne(models.Model):
foo = models.CharField(max_length=25)
def save(self,*args,**kwargs):
a = ModelTwo.objects.get(pk=arbitrary_pk)
a.somefield.add(self) # I am worried about this line here
super(ModelOne,self).save(*args,**kwargs)
class ModelTwo(models.Model):
somefield = models.ManyToManyField(ModelOne)
The line where I am adding self to a.somefield is the line I am worried about. How can I do this without error? Currently, I am getting:
ValueError: Cannot add "<ModelOne>": the value for field "modelone" is None
Thanks in advance
You can't do that because when you call .add() you have yet to save your model. That means that the model may not have been created (so it doesn't have an ID yet).
Basically you're telling Django to update the Foreign Key with something that doesn't exist yet (NULL), which will error out. You need to make sure the model has been created before you can set the foreign key.
try moving the a.somefield.add(self) to AFTER the super() call.
You cannot save many to may field before calling actual save method, you modify code like,
def save(self,*args,**kwargs):
super(ModelOne,self).save(*args,**kwargs) # Here your self has been saved
a = ModelTwo.objects.get(pk=arbitrary_pk)
a.somefield.add(self) # Now your self can be add as ManyToMany as it is already saved in db
I hope this help.
Add the instance to the many to many field after calling the save method.
class ModelOne(models.Model):
foo = models.CharField(max_length=25)
def save(self,*args,**kwargs):
super(ModelOne,self).save(*args,**kwargs)
a = ModelTwo.objects.get(pk=arbitrary_pk)
a.somefield.add(self) #add self to the object manytomany.
a.save() #save the object.
class ModelTwo(models.Model):
somefield = models.ManyToManyField(ModelOne)
You need to save the self object first. The many to many relation needs to have the related object saved in the database first, inorder to define the relationship. Then, define the relationship using a.somefield.add(self). Then, save the a object. Otherwise, the relation won't be committed in the database.
I ended up utilizing post_save to get this to work.
I recently added a new method to my model "News":
def slug(self):
return slugify(self.title)
However I can't seem to call it from anywhere. Imagine I have a News object called n. When trying to call
n.slug()
I always get an error like:
AttributeError: 'News' object has no attribute 'slug'
I'm a total beginner at Django and Python and I'm sure this is just a stupid mistake on my side. By the way I tried restarting the dev server and syncing the db after I added the method, both don't change a thing. Note that I have used model methods like this before without a problem :S
Edit:
Here is the model:
from django.template.defaultfilters import slugify
class News(models.Model):
title = models.CharField(max_length=100)
[...]
def slug(self):
return slugify(self.title)
Here is some example code on how I call the method. I first tried to call it in a template, but it didn't work. Then I changed my view so it just returns the slug, but the error remains. Same when I try it in the shell.
from fbki.models import News
def news_detail(request, slug, news_id):
news = News.objects.get(id = news_id)
return HttpResponse(news.slug())
There are, no errors. Please check what class you by
from fbki.models import News
it looks like you have two copies in project, and modify other class. You check by renaming your class News to News1. It you will same error - I'm right.
I've had some errors similar to this.
I believe that the problem is an inconsistency between your model and the actual schema in your database.
Run manage.py sql myapp and verify the contents match what is in sql> show schema (etc.)
If they don't match, you have to use your SQL client and drop the old table so that you can re-run manage.py syncdb to make them match again.
Your method should work once the schema are present.
How do you store a "blob" of binary data using Django's ORM, with a PostgreSQL backend? Yes, I know Django frowns upon that sort of thing, and yes, I know they prefer you use the ImageField or FileField for that, but suffice it to say, that's impractical for my application.
I've tried hacking it by using a TextField, but I get occassional errors when my binary data doesn't strictly confirm to the models encoding type, which is unicode by default. e.g.
psycopg2.DataError: invalid byte sequence for encoding "UTF8": 0xe22665
If you're using Django >= 1.6, there's a BinaryField
This snippet any good:
http://djangosnippets.org/snippets/1597/
This is possibly the simplest solution for storing binary data in a
TextField.
import base64
from django.db import models
class Foo(models.Model):
_data = models.TextField(
db_column='data',
blank=True)
def set_data(self, data):
self._data = base64.encodestring(data)
def get_data(self):
return base64.decodestring(self._data)
data = property(get_data, set_data)
There's a couple of other snippets there that might help.
I have been using this simple field for 'mysql' backend, you can modify it for other backends
class BlobField(models.Field):
description = "Blob"
def db_type(self, connection):
return 'blob'
Also, check out Django Storages' Database Storage:.
I haven't used it yet, but it looks awesome and I'm going to start using it as soon as I Post My Answer.
It seems that the default primary key is int. Is there anyway to use the big integer for the autofield as the primary key?
I would suggest you use a newer Django. Official Django documentation doesn't go farther back than 1.3 now. And 1.3 is insecure and unsupported. I realize the question was asked over 3 years ago, but since there is still no accepted answer I will give it a shot.
In Django 1.6.5 you can just do this in your model:
class MyModel(models.Model):
id = models.BigIntegerField(unique=True, primary_key=True)
The primary_key=True will override the default id on the model. In use this field auto increments with each new model object. It just works!
There are a couple of ways I can see to implement this. Either way, you have to define your pk field.
First of all, just create your own id field and override the save method.
modelname(models.Model):
# model definition
def save(self):
self.pkfield = nextIntFucntion()
super(modelname, self).save()
The nextIntFunction() is easy enough with a query of objects ordered by id, then get the id+1
I also found this link BigIntegerField and BigAutoField which seems to solve the problem, but I have not tested it myself
I met the same question too.
I have add some code like
User._meta.has_auto_field = True
User._meta.auto_field = id
And I define the id field to BigIntegerField(primary_key=True)
After I use user.Save(), user.id will have its id, don't need I query again.
I think it works, but it is not a beautiful solution, so I still finding a good way.
Since Django 1.10 you can use BigAutoField as described on documentation works exactly as AutoField but it is guaranteed to fit numbers from 1 to 9223372036854775807.
So you can use it like:
class SomeModel(models.Model):
id = models.BigAutoField()
...
You can hack Django and change the default auto-keys to the right values. Check out:
http://code.djangoproject.com/browser/django/trunk/django/db/backends/mysql/creation.py
from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
# This dictionary maps Field objects to their associated MySQL column
# types, as strings. Column-type strings can contain format strings; they'll
# be interpolated against the values of Field.__dict__ before being output.
# If a column type is set to None, it won't be included in the output.
data_types = {
'AutoField': 'integer AUTO_INCREMENT',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
You can modify this using a patch in your own code:
DatabaseCreation.data_types['AutoField'] = 'bigint AUTO_INCREMENT'
You will also have to patch the AutoField class:
http://code.djangoproject.com/browser/django/trunk/django/db/models/fields/__init__.py
(untested code, good luck)
http://docs.djangoproject.com/en/dev/topics/db/models/
class BigIntegerField([**options])
available option is :
primary_key
If True, this field is the primary key for the model.
And after all you do a south migration:
ALTER TABLE mytable MODIFY COLUMN myid BIGINT(20) NOT NULL AUTO_INCREMENT;
You are right, sorry. The neccessary snippet is here:
http://djangosnippets.org/snippets/1244/
Allows to create bigint (mysql), bigserial (psql), or NUMBER(19) (oracle) fields which have auto-increment set by using the AutoField of django, therefore ensuring that the ID gets updated in the instance when calling its 'save()' method.
If you would only subclass IntegerField to BigIntegerField and use that as your primary key, your model instance you create would not get the id attribute set when calling 'save()', buy instead you would have to query and load the instance from the DB again to get the ID.
These snippets work. Use the BigAutoField class as your primary key on your model and it works seemlessly without any hacking.