or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Django Object Actions

1

2

A Django app for adding object tools for models in the admin interface. Django Object Actions extends Django's admin action framework to work on individual model instances in addition to querysets, enabling custom actions on both change and changelist views.

3

4

## Package Information

5

6

- **Package Name**: django-object-actions

7

- **Language**: Python

8

- **Installation**: `pip install django-object-actions`

9

- **Django Compatibility**: Django admin framework required

10

- **Python Compatibility**: 3.9+

11

12

## Core Imports

13

14

```python

15

from django_object_actions import DjangoObjectActions, action, takes_instance_or_queryset

16

```

17

18

For advanced use cases:

19

20

```python

21

from django_object_actions import BaseDjangoObjectActions

22

```

23

24

## Basic Usage

25

26

```python

27

from django.contrib import admin

28

from django_object_actions import DjangoObjectActions, action

29

30

class ArticleAdmin(DjangoObjectActions, admin.ModelAdmin):

31

@action(label="Publish", description="Submit this article")

32

def publish_this(self, request, obj):

33

# Your custom logic here

34

obj.status = 'published'

35

obj.save()

36

self.message_user(request, f"Published {obj.title}")

37

38

change_actions = ('publish_this',)

39

changelist_actions = ()

40

41

admin.site.register(Article, ArticleAdmin)

42

```

43

44

## Setup Requirements

45

46

1. Add to Django settings:

47

```python

48

INSTALLED_APPS = [

49

# ... other apps

50

'django_object_actions',

51

# ... other apps

52

]

53

```

54

55

2. Inherit from `DjangoObjectActions` mixin in your `ModelAdmin` classes.

56

57

## Capabilities

58

59

### Admin Mixin Classes

60

61

Core mixin classes that extend Django ModelAdmin to support object actions.

62

63

#### BaseDjangoObjectActions

64

65

Base mixin providing object action functionality without default templates.

66

67

```python { .api }

68

class BaseDjangoObjectActions:

69

"""

70

ModelAdmin mixin to add new actions just like adding admin actions.

71

72

Attributes:

73

- change_actions: list of str - Action names for change view

74

- changelist_actions: list of str - Action names for changelist view

75

- tools_view_name: str - URL name for the actions view

76

"""

77

78

change_actions = []

79

changelist_actions = []

80

tools_view_name = None

81

82

def get_change_actions(self, request, object_id, form_url):

83

"""Override to customize what actions appear in change view."""

84

85

def get_changelist_actions(self, request):

86

"""Override to customize what actions appear in changelist view."""

87

```

88

89

#### DjangoObjectActions

90

91

Main mixin that includes admin templates and extends BaseDjangoObjectActions.

92

93

```python { .api }

94

class DjangoObjectActions(BaseDjangoObjectActions):

95

"""

96

Complete mixin with templates for Django admin object actions.

97

98

Attributes:

99

- change_form_template: str - Template for change form

100

- change_list_template: str - Template for changelist

101

"""

102

103

change_form_template = "django_object_actions/change_form.html"

104

change_list_template = "django_object_actions/change_list.html"

105

```

106

107

### Action Decorators

108

109

Decorators for enhancing action functions with metadata and behavior.

110

111

#### @action Decorator

112

113

Adds metadata and behavior configuration to action functions.

114

115

```python { .api }

116

def action(

117

function=None,

118

*,

119

permissions=None,

120

description=None,

121

label=None,

122

attrs=None,

123

methods=('GET', 'POST'),

124

button_type='a'

125

):

126

"""

127

Add attributes to an action function.

128

129

Parameters:

130

- permissions: list of str - Required permissions

131

- description: str - Tooltip description for the button

132

- label: str - Display label for the button (defaults to function name)

133

- attrs: dict - HTML attributes for the button element

134

- methods: tuple - Allowed HTTP methods (default: ('GET', 'POST'))

135

- button_type: str - Button type ('a' for link, 'form' for form submission)

136

137

Returns:

138

Decorated function with added attributes

139

"""

140

```

141

142

**Usage Examples:**

143

144

```python

145

@action(label="Publish Article", description="Mark this article as published")

146

def publish_article(self, request, obj):

147

obj.status = 'published'

148

obj.save()

149

150

@action(

151

permissions=['publish'],

152

description='Submit for publication',

153

attrs={'class': 'btn-primary'},

154

methods=('POST',),

155

button_type='form'

156

)

157

def submit_for_publication(self, request, obj):

158

obj.submit_for_review()

159

```

160

161

#### @takes_instance_or_queryset Decorator

162

163

Converts admin actions to work with both individual objects and querysets.

164

165

```python { .api }

166

def takes_instance_or_queryset(func):

167

"""

168

Make standard Django admin actions compatible with object actions.

169

170

Converts single model instances to querysets, allowing reuse of

171

existing admin actions as object actions.

172

173

Parameters:

174

- func: function - Admin action function that expects a queryset

175

176

Returns:

177

Decorated function that works with both instances and querysets

178

"""

179

```

180

181

**Usage Example:**

182

183

```python

184

@takes_instance_or_queryset

185

def mark_as_featured(self, request, queryset):

186

queryset.update(featured=True)

187

self.message_user(request, f"Marked {queryset.count()} items as featured")

188

189

# Can be used in both contexts:

190

change_actions = ['mark_as_featured'] # Works on single objects

191

actions = ['mark_as_featured'] # Works on querysets

192

```

193

194

### Action Implementation Patterns

195

196

#### Change Actions (Single Object)

197

198

Actions that operate on individual model instances in the change view.

199

200

```python

201

class MyModelAdmin(DjangoObjectActions, admin.ModelAdmin):

202

def my_change_action(self, request, obj):

203

"""

204

Action function for change view.

205

206

Parameters:

207

- request: HttpRequest - Django request object

208

- obj: Model instance - The object being acted upon

209

210

Returns:

211

- None: Redirects back to change view

212

- HttpResponse: Custom response (redirect, render, etc.)

213

"""

214

# Your logic here

215

obj.some_field = 'new_value'

216

obj.save()

217

218

# Optional: Send message to user

219

self.message_user(request, "Action completed successfully")

220

221

# Optional: Custom redirect

222

# return HttpResponseRedirect('/custom/url/')

223

224

change_actions = ('my_change_action',)

225

```

226

227

#### Changelist Actions (Queryset)

228

229

Actions that operate on querysets in the changelist view.

230

231

```python

232

class MyModelAdmin(DjangoObjectActions, admin.ModelAdmin):

233

def my_changelist_action(self, request, queryset):

234

"""

235

Action function for changelist view.

236

237

Parameters:

238

- request: HttpRequest - Django request object

239

- queryset: QuerySet - The selected objects

240

241

Returns:

242

- None: Redirects back to changelist view

243

- HttpResponse: Custom response

244

"""

245

# Bulk operation

246

updated = queryset.update(status='processed')

247

self.message_user(request, f"Updated {updated} items")

248

249

changelist_actions = ('my_changelist_action',)

250

```

251

252

#### Dynamic Action Control

253

254

Control which actions are available based on context.

255

256

```python

257

class MyModelAdmin(DjangoObjectActions, admin.ModelAdmin):

258

def get_change_actions(self, request, object_id, form_url):

259

"""

260

Dynamically determine available change actions.

261

262

Parameters:

263

- request: HttpRequest - Current request

264

- object_id: str - Primary key of the object

265

- form_url: str - URL of the change form

266

267

Returns:

268

list of str - Action names to display

269

"""

270

actions = list(super().get_change_actions(request, object_id, form_url))

271

272

# Example: Remove action based on user permissions

273

if not request.user.is_superuser:

274

actions = [a for a in actions if a != 'dangerous_action']

275

276

# Example: Remove action based on object state

277

obj = self.model.objects.get(pk=object_id)

278

if obj.status == 'published':

279

actions = [a for a in actions if a != 'publish_action']

280

281

return actions

282

283

def get_changelist_actions(self, request):

284

"""

285

Dynamically determine available changelist actions.

286

287

Parameters:

288

- request: HttpRequest - Current request

289

290

Returns:

291

list of str - Action names to display

292

"""

293

actions = list(super().get_changelist_actions(request))

294

295

# Example: Role-based action availability

296

if request.user.groups.filter(name='editors').exists():

297

actions.append('editor_special_action')

298

299

return actions

300

```

301

302

### Advanced Usage Patterns

303

304

#### Custom Response Handling

305

306

Actions can return custom HTTP responses for complex workflows.

307

308

```python

309

def complex_action(self, request, obj):

310

"""Action with custom response handling."""

311

from django.shortcuts import render

312

from django.http import HttpResponseRedirect

313

314

if request.method == 'POST':

315

# Process the action

316

obj.process_complex_operation()

317

self.message_user(request, "Operation completed")

318

return None # Redirect back to change view

319

320

# Show confirmation page

321

return render(request, 'admin/confirm_complex_action.html', {

322

'object': obj,

323

'title': 'Confirm Complex Action'

324

})

325

```

326

327

#### Integration with Existing Admin Actions

328

329

Reuse existing admin actions as object actions.

330

331

```python

332

class MyModelAdmin(DjangoObjectActions, admin.ModelAdmin):

333

def bulk_update_status(self, request, queryset):

334

"""Standard admin action."""

335

queryset.update(status='updated')

336

self.message_user(request, f"Updated {queryset.count()} items")

337

338

@takes_instance_or_queryset

339

def single_update_status(self, request, queryset):

340

"""Same logic, works for both single objects and querysets."""

341

return self.bulk_update_status(request, queryset)

342

343

# Available in both contexts

344

actions = ['bulk_update_status']

345

change_actions = ['single_update_status']

346

changelist_actions = ['bulk_update_status']

347

```

348

349

#### HTML Attribute Customization

350

351

Customize button appearance and behavior with HTML attributes.

352

353

```python

354

@action(

355

label="Delete Safely",

356

description="Safely delete this item with confirmation",

357

attrs={

358

'class': 'btn btn-danger',

359

'onclick': 'return confirm("Are you sure?");',

360

'data-toggle': 'tooltip',

361

'data-placement': 'top'

362

}

363

)

364

def safe_delete(self, request, obj):

365

obj.delete()

366

self.message_user(request, "Item deleted successfully")

367

```

368

369

## Error Handling

370

371

The framework handles common error scenarios:

372

373

- **Invalid action names**: Raises `Http404` if action doesn't exist

374

- **HTTP method restrictions**: Returns `HttpResponseNotAllowed` for invalid methods

375

- **Permission checking**: Integrates with Django admin's permission system

376

- **URL parameter handling**: Properly unquotes special characters in primary keys

377

378

## Template Integration

379

380

Django Object Actions provides three templates that extend Django's admin templates:

381

382

- `django_object_actions/change_form.html` - Adds action buttons to change view

383

- `django_object_actions/change_list.html` - Adds action buttons to changelist view

384

- `django_object_actions/action_trigger.html` - Renders individual action buttons

385

386

These templates automatically integrate with your existing admin customizations and preserve all Django admin functionality.