Fix for the bad behaviour of GenericForeignKey field

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
""" Contact: Filip Sobalski <pinkeen@gmail.com> """

from django.contrib.contenttypes import generic
from django.db.models import signals

class ImprovedGenericForeignKey(generic.GenericForeignKey):
	"""
	Corrects the behaviour of GenericForeignKey so even if you firstly
	assign an object to this field and then save this object - its PK 
	still gets saved in the fk_field.

	If you assign a not yet saved object to this field an exception is 
	thrown upon saving the model.
	"""
	
	class IncompleteData(Exception):
		message = 'Object assigned to field "%s" doesn\'t have a PK (save it first)!'
		
		def __init__(self, field_name):
			self.field_name = field_name
			
		def __str__(self):
			return self.message % self.field_name
			
	def contribute_to_class(self, cls, name):
		signals.pre_save.connect(self.instance_pre_save, sender=cls, weak=False)
		super(ImprovedGenericForeignKey, self).contribute_to_class(cls, name)
			
	def instance_pre_save(self, sender, instance, **kwargs):
		"""
		Ensures that if GenericForeignKey has an object assigned
		that the fk_field stores the object's PK.
		"""
		
		""" If we already have pk set don't do anything... """
		if getattr(instance, self.fk_field) is not None: return
			
		value = getattr(instance, self.name)
		
		""" 
		If no objects is assigned then we leave it as it is. If null constraints
		are present they should take care of this, if not, well, it's not my fault;)
		"""
		if value is not None:
			fk = value._get_pk_val()
			
			if fk is None:
				raise self.IncompleteData(self.name)
		
			setattr(instance, self.fk_field, fk)

More like this

  1. Improved Pickled Object Field by taavi223 4 years, 8 months ago
  2. Automatically slugify slug fields in your models by Aliquip 7 years, 1 month ago
  3. "Approved" field with timestamp by miracle2k 6 years, 9 months ago
  4. create_object and update_object for newforms by danjak 7 years, 1 month ago
  5. Binding signals to abstract models by andreterra 1 year, 11 months ago

Comments

(Forgotten your password?)