Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

# -*- coding: UTF-8 -*- 

# Copyright 2010-2015 Luc Saffre 

# License: BSD (see file COPYING for details) 

 

""" 

Database models for `lino.modlib.gfks`. 

 

See also unit test :doc:`/dev/gfks`. 

 

.. autosummary:: 

 

""" 

from builtins import str 

from builtins import object 

 

 

from django.contrib.contenttypes.models import ContentType, models 

 

from django.conf import settings 

from django.utils.translation import ugettext_lazy as _ 

from django.db.utils import DatabaseError 

from django.db.models import FieldDoesNotExist 

 

from lino.core.roles import SiteStaff 

from lino.api import dd, rt 

from lino.utils.xmlgen.html import E 

from lino.utils import join_elems 

 

from lino.core.utils import get_models 

 

 

class ContentTypes(dd.Table): 

    """Default table for `django.contrib.ContentType`. 

 

 

    .. attribute:: base_classes 

 

        Display a clickable list of all MTI parents, i.e. base models 

 

    """ 

    model = 'contenttypes.ContentType' 

 

    required_roles = dd.required(SiteStaff) 

 

    detail_layout = """ 

    id app_label model base_classes 

    HelpTextsByModel 

    BrokenGFKsByModel 

    """ 

 

    @dd.displayfield(_("Base classes")) 

    def base_classes(self, obj, ar): 

        if obj is None: 

            return "" 

        chunks = [] 

 

        def add(cl): 

            for b in cl.__bases__: 

                add(b) 

            # : 

            if issubclass(cl, dd.Model) and cl is not dd.Model \ 

               and cl._meta.managed: 

                if getattr(cl, '_meta', False) and not cl._meta.abstract: 

                    #~ logger.info("20120205 adding(%r)",cl) 

                    ct = ContentType.objects.get_for_model(cl) 

                    chunks.append( 

                        ar.obj2html(ct, str(cl._meta.verbose_name))) 

        #~ add(obj.model_class()) 

        cl = obj.model_class() 

        # e.g. if database is nor synchronized 

        if cl is not None: 

            for b in cl.__bases__: 

                add(b) 

        return E.p(*join_elems(chunks, sep=', ')) 

 

 

@dd.python_2_unicode_compatible 

class HelpText(dd.Model): 

    """A custom help text to be displayed for a given field.""" 

    class Meta(object): 

        app_label = 'gfks' 

        verbose_name = _("Help Text") 

        verbose_name_plural = _("Help Texts") 

 

    content_type = models.ForeignKey('contenttypes.ContentType', 

                                     verbose_name=_("Model")) 

    field = models.CharField(_("Field"), max_length=200) 

 

    help_text = dd.RichTextField(_("HelpText"), 

                                 blank=True, null=True, format='plain') 

 

    def __str__(self): 

        return self.content_type.app_label + '.' \ 

            + self.content_type.model + '.' + self.field 

 

    @dd.chooser(simple_values=True) 

    def field_choices(cls, content_type): 

        l = [] 

        if content_type is not None: 

            model = content_type.model_class() 

            meta = model._meta 

            for f in meta.fields: 

                if not getattr(f, '_lino_babel_field', False): 

                    l.append(f.name) 

            for f in meta.many_to_many: 

                l.append(f.name) 

            for f in meta.virtual_fields: 

                l.append(f.name) 

            for a in model.get_default_table().get_actions(): 

                l.append(a.action.action_name) 

            l.sort() 

        return l 

 

    #~ def get_field_display(cls,fld): 

        #~ return fld 

 

    @dd.virtualfield(models.CharField(_("Verbose name"), max_length=200)) 

    def verbose_name(self, request): 

        m = self.content_type.model_class() 

        de = m.get_default_table().get_data_elem(self.field) 

        if isinstance(de, models.Field): 

            return "%s (%s)" % (str(de.verbose_name), 

                                str(_("database field"))) 

        if isinstance(de, dd.VirtualField): 

            return str(de.return_type.verbose_name) 

        if isinstance(de, dd.Action): 

            return str(de.label) 

        return str(de) 

 

 

class HelpTexts(dd.Table): 

    required_roles = dd.required(SiteStaff) 

    model = 'gfks.HelpText' 

    column_names = "field verbose_name help_text id content_type" 

 

 

class HelpTextsByModel(HelpTexts): 

    master_key = 'content_type' 

 

 

class BrokenGFKs(dd.VirtualTable): 

    """Shows all database objects (model instances) who have a broken 

    GeneriForeignKey field. 

 

 

    """ 

    label = _("Broken GFKs") 

    required_roles = dd.required(SiteStaff) 

 

    column_names = "database_model database_object message todo" 

 

    @classmethod 

    def get_data_rows(self, ar): 

        f = settings.SITE.kernel.get_broken_generic_related 

        for model in get_models(include_auto_created=True): 

            for obj in f(model): 

                yield obj 

 

    @dd.displayfield(_("Database object")) 

    def database_object(self, obj, ar): 

        return ar.obj2html(obj) 

 

    @dd.displayfield(_("Message")) 

    def message(self, obj, ar): 

        return obj._message 

 

    @dd.displayfield(_("Action")) 

    def todo(self, obj, ar): 

        return obj._todo 

 

    @dd.displayfield(_("Database model")) 

    def database_model(self, obj, ar): 

        ct = ContentType.objects.get_for_model(obj.__class__) 

        return ar.obj2html(ct) 

 

 

class BrokenGFKsByModel(BrokenGFKs): 

    master = 'contenttypes.ContentType' 

 

    column_names = "database_object message todo" 

 

    @classmethod 

    def get_data_rows(self, ar): 

        mi = ar.master_instance 

        f = settings.SITE.kernel.get_broken_generic_related 

        if mi is not None: 

            for obj in f(mi.model_class()): 

                yield obj 

 

    @classmethod 

    def get_pk_field(self): 

        return settings.SITE.site_config._meta.get_field('id') 

 

    @classmethod 

    def get_row_by_pk(self, ar, pk): 

        mi = ar.master_instance 

        if mi is None: 

            return None 

        M = mi.model_class() 

        try: 

            return M.objects.get(pk=pk) 

        except ValueError: 

            return None 

        except M.DoesNotExist: 

            return None 

 

    @classmethod 

    def get_row_permission(cls, obj, ar, state, ba): 

        return True 

 

 

@dd.receiver(dd.pre_ui_build) 

def my_pre_ui_build(sender, **kw): 

    try: 

        HelpText = rt.modules.gfks.HelpText 

        for ht in HelpText.objects.filter(help_text__isnull=False): 

            # dd.logger.info("20120629 %s.help_text", ht) 

            try: 

                dd.resolve_field(str(ht)).help_text = ht.help_text 

            except FieldDoesNotExist as e: 

                #~ logger.debug("No help texts : %s",e) 

                pass 

    except DatabaseError as e: 

        dd.logger.debug("No help texts : %s", e) 

        pass 

 

 

# cause `fab mm` to generate translatable strings from Django's 

# original module since those translations are not loaded. 

_("content type") 

_("content types")