Showing posts with label django-admin. Show all posts
Showing posts with label django-admin. Show all posts

Saturday, April 15, 2017

Generic relations in Django

While using django's content management system (admin), for adding different objects on it, you may want things like audit notes, that can be used for reference in the future or get some more info. you have two choice -


  1. Add a explicit field to the object, though the down side is you will need to add that extra field with all the objects where you want note.
  2. Create a generic model which can be used with different objects in your app. 

It's no brainer between above two choice, answer is 2nd. Generic relations are at help.

You can checkout django-contrib-comments, it's one of the example of generic relations. Let's take example of how Notes like foreign key reference can be added freely to any model in your app.

notes/models.py
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class Note(models.Model):
    note = models.TextField("note",
                            max_length=2000)
    date = models.DateTimeField(auto_now_add=True)
    # Below the mandatory fields for generic relation
    content_type = models.ForeignKey(
        ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    class Meta:
        verbose_name = 'Staff Note'

    def __unicode__(self):
        return self.date.strftime("%B %d, %Y")


Now, this Notes object can be referenced with any other model you want to use it with. Here is one example -

mymodel/models.py
from django.contrib.contenttypes.fields import GenericRelation
from notes.models import Note


class MyModel(models.Model):
    name = models.CharField("Name", max_length=100)
    notes = GenericRelation(Note)

When you run migration, it doesn't add anything in MyModel, as its generic relation it gets its references via django content type and object id.

How to add it in admin?

notes/admin.py
from django.contrib.contenttypes.admin import GenericTabularInline
from .models import Note

class NoteInline(GenericTabularInline):
    model = Note
    extra = 0


mymodel/admin.py
from misc.admin import NoteInline
from .models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    inlines = [NoteInline, ]

admin.site.register(MyModel, MyModelAdmin)

And you are all set. It's easy to plug, efficient, and clean implementation. Good luck!

Wednesday, August 29, 2012

Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.

Today while accessing django-admin to update certain information I was keep getting this error on Save - 

Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.

Platform - django 1.3.1, mysql 5.5

While doing some initial research I came across its happening because of, when you are trying to insert something from admin into the table, first its inserting into temp table or you are reading from temp table and trying to insert into main table. It considers temp table as transactional table. according to following article -


However, it wasn't much of help. 

You should read about different types of binlog format - http://dev.mysql.com/doc/refman/5.1/en/binary-log-setting.html

you can simply switch to 'MIXED' and that might solve your problem -
SET GLOBAL binlog_format = 'MIXED'; 

If it doesn't then, read further and see different scenarios why it was happening.

I did further research and come across another thread where it was mentioned that, it might be happening because of certain tables are belog to MyISAM Engine, whereas certain tables belong to InnoDB.  I checked my db, and found out that it was correct! 

Tables for which I had downloaded script from server (which runs under mysql 5.0) had default Engine as MyISAM, and my local mysql is 5.5 which has default Engine listed as InnoDB. 

Unless you have specific table that needs a MyISAM specific feature such as fulltext indexes, you should always user InnoDB as Engine as per the most of the recommendations online and by mysql.

As of MySQL 5.5, InnoDB is the default storage Engine. and previous versions had MyISAM as default storage Engine. (reference http://dev.mysql.com/doc/refman/5.5/en/innodb-default-se.html)

to check if your tables using InnoDB as default engine, you can try below command -
SHOW VARIABLES LIKE 'have_innodb';

Below will show all engines for your mysqldb, and which one is default:
  
SHOW ENGINES;

You can check by generating create table script to check if its running under InnoDB or MyISAM.

CREATE TABLE `table_name` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(500) NOT NULL
  PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1$$


That means its running under MyISAM engine.

In order to change it to run under innodb, you can execute below alter statement -

ALTER TABLE table_name ENGINE=InnoDB;

On running above you might run into,

0 20:55:09 ALTER TABLE table_name ENGINE=InnoDB Error Code: 1217. Cannot delete or update a parent row: a foreign key constraint fails

This might be because foreign key been used by other tables, if we are updating the Engine for the table, you might want to go in order of foreign key reference.

Find out which tables are on InnoDB -


SELECT table_schema, table_name
FROM INFORMATION_SCHEMA.TABLES
WHERE engine = 'innodb'


If you running into this issue, follow above steps and it should be fine! Comments, Feedback welcome.




Sunday, July 15, 2012

Django Application Image issues while running on mac

If you are using django and getting jpg adapter error on image upload or while running the app on rendering the jpeg image, in that case follow below instructions. The error is most likely because of installation of jpeg in environment.


You have to install support for JPEG, for example in mac use homebrew for installation and follow below instructions - 

1. Uninstall PIL
    sudo pip uninstall PIL

2. Install JPEG
    brew install jpeg

3. Install PIL again
    sudo pip install PIL

for ubuntu users use below command -
sudo apt-get install libjpeg62-dev