or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-integration.mdcountries-registry.mddjango-rest-framework.mdform-fields-widgets.mdgraphql-support.mdindex.mdmodel-fields.mdtemplate-tags.md

form-fields-widgets.mddocs/

0

# Form Fields and Widgets

1

2

Specialized Django form fields and widgets for country selection with lazy-loaded choices, flag display support, and JavaScript integration. These components provide enhanced user interfaces for country selection in Django forms.

3

4

## Capabilities

5

6

### Form Fields

7

8

Django form fields that provide country selection with lazy-loaded choices and proper validation.

9

10

```python { .api }

11

class LazyTypedChoiceField(forms.TypedChoiceField):

12

"""

13

Form field for single country selection with lazy-loaded country choices.

14

"""

15

choices: Any

16

widget: LazySelect

17

18

class LazyTypedMultipleChoiceField(forms.TypedMultipleChoiceField):

19

"""

20

Form field for multiple country selection with lazy-loaded country choices.

21

"""

22

choices: Any

23

widget: LazySelectMultiple

24

```

25

26

### Widgets

27

28

Django form widgets with enhanced country selection interfaces and flag display capabilities.

29

30

```python { .api }

31

class LazySelect(widgets.Select):

32

"""

33

Select widget with lazy-loaded country choices.

34

"""

35

def __init__(self, attrs=None, choices=()):

36

"""

37

Initialize select widget with lazy choice loading.

38

39

Parameters:

40

- attrs: dict - HTML attributes for widget

41

- choices: iterable - Choice options (loaded lazily)

42

"""

43

44

class LazySelectMultiple(widgets.SelectMultiple):

45

"""

46

Multiple select widget with lazy-loaded country choices.

47

"""

48

def __init__(self, attrs=None, choices=()):

49

"""

50

Initialize multiple select widget with lazy choice loading.

51

52

Parameters:

53

- attrs: dict - HTML attributes for widget

54

- choices: iterable - Choice options (loaded lazily)

55

"""

56

57

class CountrySelectWidget(LazySelect):

58

"""

59

Enhanced country select widget with flag display and JavaScript integration.

60

"""

61

def __init__(

62

self,

63

layout=None,

64

attrs=None,

65

choices=(),

66

flag_url=None

67

):

68

"""

69

Initialize country select widget with flag support.

70

71

Parameters:

72

- layout: str - Widget layout template

73

- attrs: dict - HTML attributes for widget

74

- choices: iterable - Country choices

75

- flag_url: str - Flag image URL pattern

76

"""

77

```

78

79

## Usage Examples

80

81

### Basic Form Usage

82

83

```python

84

from django import forms

85

from django_countries.fields import LazyTypedChoiceField, LazyTypedMultipleChoiceField

86

from django_countries import countries

87

88

class PersonForm(forms.Form):

89

# Single country selection

90

country = LazyTypedChoiceField(choices=countries)

91

92

# Multiple country selection

93

visited_countries = LazyTypedMultipleChoiceField(

94

choices=countries,

95

required=False

96

)

97

98

class EventForm(forms.Form):

99

# With custom widget attributes

100

country = LazyTypedChoiceField(

101

choices=countries,

102

widget=forms.Select(attrs={

103

'class': 'form-control',

104

'data-placeholder': 'Select country'

105

})

106

)

107

```

108

109

### Model Form Integration

110

111

```python

112

from django import forms

113

from django_countries.widgets import CountrySelectWidget

114

from myapp.models import Organization

115

116

class OrganizationForm(forms.ModelForm):

117

class Meta:

118

model = Organization

119

fields = ['name', 'country', 'operating_countries']

120

widgets = {

121

'country': CountrySelectWidget(attrs={

122

'class': 'country-select'

123

}),

124

'operating_countries': forms.SelectMultiple(attrs={

125

'class': 'multi-country-select'

126

})

127

}

128

```

129

130

### Custom Widget Configuration

131

132

```python

133

from django_countries.widgets import CountrySelectWidget

134

135

class CustomCountryForm(forms.Form):

136

country = forms.CharField(

137

widget=CountrySelectWidget(

138

flag_url="custom/flags/{code}.png",

139

attrs={

140

'class': 'custom-country-widget',

141

'onchange': 'updateFlag(this.value)'

142

}

143

)

144

)

145

```

146

147

## Widget Features

148

149

### Flag Display Integration

150

151

The CountrySelectWidget includes JavaScript for dynamic flag display:

152

153

```python

154

from django_countries.widgets import CountrySelectWidget

155

156

# Widget with flag support

157

widget = CountrySelectWidget(

158

flag_url="flags/{code_upper}.png",

159

attrs={'id': 'country_select'}

160

)

161

162

# Generated JavaScript automatically updates flag images

163

# with ID pattern: 'flag_' + widget_id

164

```

165

166

HTML template example:

167

```html

168

<form>

169

{{ form.country }}

170

<img id="flag_country_select" src="flags/__.png" alt="Flag">

171

</form>

172

```

173

174

### Lazy Choice Loading

175

176

Widgets support lazy choice loading to avoid loading country data until needed:

177

178

```python

179

from django_countries.widgets import LazySelect

180

from django_countries import countries

181

182

# Choices loaded only when widget is rendered

183

widget = LazySelect(choices=countries)

184

185

# Works with filtered countries too

186

filtered_countries = Countries()

187

filtered_countries.only = ["US", "CA", "MX"]

188

widget = LazySelect(choices=filtered_countries)

189

```

190

191

### Custom Choice Lists

192

193

```python

194

from django_countries import Countries

195

196

# Create custom countries instance

197

asia_countries = Countries()

198

asia_countries.only = ["CN", "JP", "KR", "IN", "TH", "VN"]

199

200

class AsiaEventForm(forms.Form):

201

country = LazyTypedChoiceField(

202

choices=asia_countries,

203

widget=CountrySelectWidget()

204

)

205

```

206

207

## Widget Mixins

208

209

### LazyChoicesMixin

210

211

Mixin providing lazy choice loading functionality for Django < 5.0 compatibility:

212

213

```python { .api }

214

class LazyChoicesMixin:

215

"""Mixin for widgets that support lazy-loaded choices."""

216

217

def get_choices(self) -> List[List[Union[int, str]]]:

218

"""Get choices, evaluating lazy choices if needed."""

219

220

def set_choices(self, value):

221

"""Set widget choices."""

222

223

choices = property(get_choices, set_choices)

224

```

225

226

### LazySelectMixin

227

228

Combined mixin for select widgets with lazy choices:

229

230

```python { .api }

231

class LazySelectMixin(LazyChoicesMixin):

232

"""Mixin combining lazy choices with select widget functionality."""

233

234

def __deepcopy__(self, memo):

235

"""Deep copy widget with choices preservation."""

236

```

237

238

## Advanced Widget Customization

239

240

### Custom Flag URL Patterns

241

242

Configure different flag image patterns:

243

244

```python

245

# Different flag formats

246

widget1 = CountrySelectWidget(flag_url="flags/4x3/{code}.svg")

247

widget2 = CountrySelectWidget(flag_url="https://flags.api.com/{code_upper}.png")

248

widget3 = CountrySelectWidget(flag_url="assets/country-flags/{code}-flag.gif")

249

```

250

251

Available template variables:

252

- `{code}`: lowercase country code (e.g., "us")

253

- `{code_upper}`: uppercase country code (e.g., "US")

254

255

### JavaScript Integration

256

257

The widget automatically generates JavaScript for flag updates:

258

259

```javascript

260

// Auto-generated JavaScript pattern

261

var e=document.getElementById('flag_' + this.id);

262

if (e) e.src = 'flags/{code}.gif'

263

.replace('{code}', this.value.toLowerCase() || '__')

264

.replace('{code_upper}', this.value.toUpperCase() || '__');

265

```

266

267

### Custom Widget Templates

268

269

For advanced customization, create custom widget templates:

270

271

```python

272

class CustomCountryWidget(CountrySelectWidget):

273

template_name = 'custom_widgets/country_select.html'

274

275

def get_context(self, name, value, attrs):

276

context = super().get_context(name, value, attrs)

277

context['flag_url_pattern'] = self.flag_url

278

return context

279

```

280

281

## Form Integration Patterns

282

283

### With Django Crispy Forms

284

285

```python

286

from crispy_forms.helper import FormHelper

287

from crispy_forms.layout import Layout, Field

288

289

class CountryForm(forms.Form):

290

country = LazyTypedChoiceField(choices=countries)

291

292

def __init__(self, *args, **kwargs):

293

super().__init__(*args, **kwargs)

294

self.helper = FormHelper()

295

self.helper.layout = Layout(

296

Field('country', css_class='country-select')

297

)

298

```

299

300

### Custom Validation

301

302

```python

303

class StrictCountryForm(forms.Form):

304

country = LazyTypedChoiceField(choices=countries)

305

306

def clean_country(self):

307

country = self.cleaned_data['country']

308

if not country:

309

raise forms.ValidationError("Country is required")

310

311

# Additional validation

312

if country not in ["US", "CA", "MX"]:

313

raise forms.ValidationError("Only North American countries allowed")

314

315

return country

316

```

317

318

### Dynamic Widget Configuration

319

320

```python

321

class DynamicCountryForm(forms.Form):

322

def __init__(self, *args, region=None, **kwargs):

323

super().__init__(*args, **kwargs)

324

325

if region == 'europe':

326

eu_countries = Countries()

327

eu_countries.only = ["DE", "FR", "IT", "ES", "NL", "BE"]

328

self.fields['country'] = LazyTypedChoiceField(choices=eu_countries)

329

else:

330

self.fields['country'] = LazyTypedChoiceField(choices=countries)

331

```