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

Composite unique constraint

Composite unique constraint are very common in real database entities. In Django models, those constraints are expressed by the unique_together property of the Meta class.
Lets say that we have an Django model class:
class ModelA(models.Model):
  property1 = models.CharField(max_length=255, null=True)
  property2 = models.IntegerField()

  class Meta(object):
    unique_together = ('property1', 'property2')

It looks fine, now lets say that we want to save something in this model:
m3 = ModelA(property1=None, property2=1)
m3.save()
m4 = ModelA(property1=None, property2=1)
m4.save()

What we could expect is that the second save will fail because of the composite unique constraint. What actually will happen is that there will be two rows in db with property1 set to NULL and property2 set to 1. This is because the SQL standard define that NULL is not a value but the state so in that case the NULL value is not treat as unique accros the rows.  
To solve the issue we have to take care about checking the uniqueness on the Django model level. The save method of the models has to be overwrite. Below is the example how to define abstract class which can be used instead of Django models.Model class.

class Model(models.Model):
  class Meta(object):
    abstract = True

  def _check_uniqueness(self):
    nullable_field_names = set([x.name for x in self._meta._fields() if x.null])

    for unique_together in self._meta.unique_together:
      if set(unique_together).intersection(nullable_field_names):
        values = [(x, getattr(self, x)) for x in unique_together]
        queryset = {}
        for field, value in values:
          if value is None:
            queryset['%s__isnull' % field] = True
          else:
            queryset[field] = value
        exists_query = self.__class__.objects.filter(**queryset)
        if self.pk is not None:
          exists_query = exists_query.exclude(id=self.id)
        if exists_query.exists():
          return unique_together
    return None

    def save(self, *args, **kwargs):
      unique_together = self._check_uniqueness()
      if unique_together is not None:
        raise db.IntegrityError('columns %s are not unique' % ', '.join(unique_together))
      super(Model, self).save(*args, **kwargs)

Remote PDB and Django

Recently I have had to debug some error in Django system. In fact the problem was somewhere inside views and the debug page did not give any important information (as usually) and randomly show different place in .py files where exception was raised. I could not put standard pdb debugger, cause the problem  appeared only on nginx+uwsgi setup. I could not reproduce it on internal django webserver.
How to put debugger in uwsgi environment? Of course we do not have access to terminal in that case but we can use remote debugger. I have found very small and simply debugger rpdb:

http://tamentis.com/projects/rpdb/ 
Simply install it by pip and then put in the code:
 
import rpdb; rpdb.set_trace()
 
By default, rpdb listen on 4444 port so the next step is to connect to it by e.g. nc:
 
$ nc zuzia 4444

[teodor@zuzia production]$ nc zuzia 4444
--Call--
> /home/teodor/project/test/lib/python2.7/site-packages/rpdb/__init__.py(37)shutdown()
-> def shutdown(self):
(Pdb) w
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/management/commands/runserver.py(107)inner_run()
-> run(self.addr, int(self.port), handler, ipv6=self.use_ipv6)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(696)run()
-> httpd.serve_forever()
  /usr/lib64/python2.7/SocketServer.py(227)serve_forever()
-> self._handle_request_noblock()
  /usr/lib64/python2.7/SocketServer.py(284)_handle_request_noblock()
-> self.process_request(request, client_address)
  /usr/lib64/python2.7/SocketServer.py(310)process_request()
-> self.finish_request(request, client_address)
  /usr/lib64/python2.7/SocketServer.py(323)finish_request()
-> self.RequestHandlerClass(request, client_address, self)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(570)__init__()
-> BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
  /usr/lib64/python2.7/SocketServer.py(639)__init__()
-> self.handle()
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(615)handle()
-> handler.run(self.server.get_app())
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(283)run()
-> self.result = application(self.environ, self.start_response)
  /home/teodor/project/test/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py(68)__call__()
-> return self.application(environ, start_response)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/handlers/wsgi.py(273)__call__()
-> response = self.get_response(request)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/handlers/base.py(111)get_response()
-> response = callback(request, *callback_args, **callback_kwargs)
  /media/Crypted/teodor/projects/test/web/views.py(525)wrapper()
-> return panel_view(request, *args, **kw)
  /media/Crypted/teodor/projects/test/web/views.py(540)test()
-> import rpdb; rpdb.set_trace()
  /home/teodor/project/test/lib/python2.7/site-packages/rpdb/__init__.py(62)set_trace()
-> debugger.shutdown()
> /home/teodor/project/test/lib/python2.7/site-packages/rpdb/__init__.py(37)shutdown()
-> def shutdown(self):
(Pdb) 

Django template tag: display some content in specified time range

Django template tags are very powerful tool for extending this template framework, in fact built-in set of filters and tags is very large but from time to time it is the need to do something custom. 
Recently I have got a task that required to display some content in specified time range. I could not find built in solution so I have prepared template tag that behave like {% if %}{% else %} tag set.

Code is available here: https://github.com/MrTheodor/django-snippets

How to use it?

Usage:
   1. Define in settings dict TIME_BLOCK with names of block that has to be
   shown on certain time:
       TIME_BLOCK = {
           'block1': {
               'from_date': datetime.datetime(2012, 04, 28, 13, 48),
               'to_date': datetime.datetime(2012, 04, 30, 13, 48),
               'show': True
           }
       }
   
   2. In template use it in such way:
       
       {% showtime block1 %}
           content that will be displayed between 2012-04-28 13:48 and 2012-04-30
           13:48
       {% else %}
           content that will be displayed before and after that time
       {% endshowtime %}

  There is also the possibility to do it in the reverse way by using option 'show'
 

Enjoy!