Django

From Mosuma
Jump to: navigation, search

Notes on Django Rest Framework (DRF)

unique_together constraints in the model

If you specify a unique_together constraint at the Django model level, DRF impose the following restrictions on your API:

  • you can only update 1 object at a time, by first listing that object in the URL, e.g., /api/object/{ID}/
  • you cannot do free form post to update an instance, i.e., you cannot just POST to the server or at the object listing DRF page a raw json snippet with object id and update values, since DRF does not know what your current instance is

If you do any of the above, DRF will complain:

{
    "non_field_errors": [
        "The fields unique_together_field1, unique_together_field2 must make a unique set."
    ]
}

This is because the single update DRF unique_together validator needs an existing instance, otherwise it assumes you are creating a new instance, and if it finds a duplicate of the unique pair, it complains.

overriding the validate() method in the serializer is useless, since the validators run before the serializers

I am still experimenting with list updates, will update when I am done.

The following are not yet tested:

  • you cannot mix update and creation of new objects in a list????

Notes on Django

Danger of using not qs

Suppose qs is a queryset, and your logic has something like

if not qs:
    qs = Model.objects.all()

BEWARE! if qs is a huge set of results, "not qs" will STALL as it tries to take the complement of the qs

Better to use

if qs is None:
    qs = Models.objects.all()
Custom locale formats FAIL for zh-hans

Same reason as the translations, you need to sym link from zh-hans - zh_Hans in order for the custom formats to work

Why Chinese translations fail to show

There is a BUG with the language code mapping in django 1.8.4:

  • While the LANGUAGES option listed in YOURPYTHONENV/lib/python2.7/site-packages/django/conf/global_settings.py list chinese as follows:
LANGUAGES = (
    ...
    ('zh-cn', gettext_noop('Simplified Chinese')),
    ('zh-hans', gettext_noop('Simplified Chinese')),
    ('zh-hant', gettext_noop('Traditional Chinese')),
    ('zh-tw', gettext_noop('Traditional Chinese')),
    ...
)

bug if your zh-hans (Chinese simplified) translations are stored as

FAILS:

APP/locale/zh-hans/LC_MESSAGES/django.po

Django FAILS to find the files, you must create a link or rename it to "zh_Hans", e.g.,

WORKS:

APP/locale/zh_Hans/LC_MESSAGES/django.po

Since this is a bug in my opinion, I prefer to create a symbolic link to the zh-hans directory:

ln -s zh-hans zh_Hans

For other related folder naming, you may reference the site APP's locale directories:

YOURPYTHONENV/lib/python2.7/site-packages/django/contrib/sites/locale
Unique together
  • unique_together will not work if one of the N fields is a foreignkey, and that key is NULL, e.g., you can have unique_together = ('slug', 'some_foreignkey'), but if your object allows null for some_foreignkey, then it is possible to create objects with multiple slugs, e.g.,
slug, some_foreignkey
slug1, null
slug1, null
slug1, null
...
  • enforce all members in the list to be REQUIRED fields

Django-cities-light

For migrations to work

  • default values for foreignkey to cities/regions/countries cannot be an object
Django OptGroups Choices

2-level choices give you a list of values organized in groups

2-level choices for Model Fields MUST have the object.ID as the KEY!!

otherwise setting initial value and submission of the value via the default django form will NOT work


Django CMS 3 migration Error

WARNING: DO NOT SET THIS PARAMETER in settings.py

CMS_RAW_ID_USERS = 200 

Comment it out:

#CMS_RAW_ID_USERS = 200 

Otherwise you will get this error when initializing the database from SCRATCH:

src#./manage.py migrate
/pythonenv/local/lib/python2.7/site-packages/cms/publisher/manager.py:5: RemovedInDjango18Warning: `PublisherManager.get_query_set` method should be renamed `get_queryset`.
  class PublisherManager(models.Man

.....
django.db.utils.ProgrammingError: relation "auth_user" does not exist
LINE 1: SELECT COUNT(*) FROM "auth_user"

Error goes away once you have created the auth_user table in the database.

schemamigration COMPULSORY for apps with existing migrations

If you are working on an app with an existing set of pre-defined migrations, you must do the following

python manage.py schemamigration YOURAPPNAME --auto
python manage.py migrate YOURAPPNAME
otherwise the changes you make to the models will not generate new tables even if you do a
python manage.py syncdb

Found this out the hard way while working on [cms_saq]

To make your changes reflected immediately in the development python server and DB, just rename the migrations folder:

mv migrations migrations.disable

reinstate the migrations directory and do an actual schemamigration when you are done modifying and testing your model.

Django-CMS

Running behind a SSL nginx proxy

If you have a nginx proxy with SSL at the gateway, while at the backend you serve Django-CMS with nginx (no SSL) with uwsgi, then you may encounter situations where some of Django-CMS admin edits stalling after submission with web-browser complaints like "blocked mixed content (https / http)", notably the "unpublish", "publish", "resolve" URLs.

To fix that, you just need to set:

1) HTTPS NGINX PROXY:

sites-enabled/gateway.conf:

location / {

   proxy_pass http://LAN_ADDRESS_RUNNING_NGINX_UWSGI/;
   proxy_set_header Host $http_host;   # required for django 1.5
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   # HTTPS -------------- combine following with django settings:
   # SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
   proxy_set_header X-Forwarded-Proto https;       # WORKS: 2016.04.04
   ....

2) DJANGO settings.py

  SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Reference:

Caching

2014.11.04

Django-CMS 3.0.x enables page CACHE to 60 seconds by default

http://django-cms.readthedocs.org/en/latest/advanced/caching.html

This causes problems with login and logout lazysignup users as follows:

  1. automatically logging in as lazysignup users
  2. fill in a form on formpage
  3. logout
  4. go the the formpage and try submitting the form again FAILS because the page is still using the old cached CSRF token
  5. Wait for 60 seconds, then the form page would have been refreshed with a new CSRF token, and a new lazysignup user would have been created for you to fill up the form again

Solution 1 (works): In your settings.py, set the following:

CMS_CACHE_DURATIONS = MINUTE        # default 60 secs
CMS_PAGE_CACHE = True               # True OK. cache non-LOGIN, non-POST
CMS_PLACEHOLDER_CACHE = False       # True NOT OK ==> Logout is cached!!!!!
CMS_PLUGIN_CACHE = True             # True OK?

This may slow down the page loads. To fix that. Do *not* logout the lazy user. Let lazy user persists. Then set CACHE_TIMEOUT = 300 sec, so that the page is cached.

Solution 2 (not tested yet): set
cache = False
in your custom plugin to bypass that
CMSPage
  • Django-CMS maintains two instances of every page in the DB, one draft, one published.
    • When a page is initially created, 1 (draft) copy is created in the DB
    • When a page is published, another copy (published) is created. The published version will be a copy, while the draft version also exists
    • The implications for this is that you cannot specify each page to be unique in the DB while designing your customer CMS-pages
CMSPlugin
  • The same applies for CMS plugins: it exists as 2 copies in the DB, one draft, one published (if published).
    • Both copies will have the exact same values, differentiated only by the CMS field cmsplugin_ptr_id
  • Other class instances associated with the plugin exists only once in the DB, but are only associated to the published instances.
    • In your CMSPlugin, you have to explicitly define a *copy_relations* method to actually copy the relations from the old plugin to the new plugin
  • Thus the best practice for CMSplugin design is to create relations from the plugin to your custom models, and not use the plugin itself as the raw model.
Django-CMS-SAQ

Example of a badly coded CMSPlugin: [Master Branch of django-cms-saq]

  • This plugin made a grave design mistake by including a unique constraint in the Question(CMSPlugin), specificially, one of its field 'slug' must be unique.
    • This creates a grave problem when the Question(CMSPlugin) gets published, Django-CMS tries but fail to create another copy of the same question plugin with the *same* slug, which violates the unique slug constraint.
    • In other words, the question plugin in cms_saq can never be published!
  • Likewise, the Answers model wrongly requires (questionid, answerslug) to be unique together, i.e.,
     unique_together = ('question', 'slug') 
    , resulting in the same problem when the plugin is published
    • publishing the plugin requires the copying of all answer relations from the old plugin (draft) to the new plugin (published), in which case, the new instance of ('question' and 'slug') answers will no longer be unique, generating another error!

There is a [branch of django-cms-saq] that takes into consideration django-1.5 requirements, including some of my contributions.