|
1 | 1 | from django.core.exceptions import ImproperlyConfigured
|
| 2 | +from django.forms import Form |
2 | 3 | from django.forms import models as model_forms
|
3 | 4 | from django.http import HttpResponseRedirect
|
4 | 5 | from django.views.generic.base import TemplateResponseMixin
|
| 6 | +from django.views.generic.detail import SingleObjectTemplateResponseMixin |
5 | 7 |
|
6 | 8 | from django_async_extensions.aviews.generic.base import AsyncView, AsyncContextMixin
|
7 | 9 | from django_async_extensions.aviews.generic.detail import (
|
8 | 10 | AsyncSingleObjectMixin,
|
| 11 | + AsyncBaseDetailView, |
9 | 12 | )
|
10 | 13 |
|
11 | 14 |
|
@@ -165,3 +168,111 @@ class AsyncBaseFormView(AsyncFormMixin, AsyncProcessFormView):
|
165 | 168 |
|
166 | 169 | class AsyncFormView(TemplateResponseMixin, AsyncBaseFormView):
|
167 | 170 | """A view for displaying a form and rendering a template response."""
|
| 171 | + |
| 172 | + |
| 173 | +class AsyncBaseCreateView(AsyncModelFormMixin, AsyncProcessFormView): |
| 174 | + """ |
| 175 | + Base view for creating a new object instance. |
| 176 | +
|
| 177 | + This requires subclassing to provide a response mixin. |
| 178 | + """ |
| 179 | + |
| 180 | + async def get(self, request, *args, **kwargs): |
| 181 | + self.object = None |
| 182 | + return await super().get(request, *args, **kwargs) |
| 183 | + |
| 184 | + async def post(self, request, *args, **kwargs): |
| 185 | + self.object = None |
| 186 | + return await super().post(request, *args, **kwargs) |
| 187 | + |
| 188 | + |
| 189 | +class AsyncCreateView(SingleObjectTemplateResponseMixin, AsyncBaseCreateView): |
| 190 | + """ |
| 191 | + View for creating a new object, with a response rendered by a template. |
| 192 | + """ |
| 193 | + |
| 194 | + template_name_suffix = "_form" |
| 195 | + |
| 196 | + |
| 197 | +class AsyncBaseUpdateView(AsyncModelFormMixin, AsyncProcessFormView): |
| 198 | + """ |
| 199 | + Base view for updating an existing object. |
| 200 | +
|
| 201 | + This requires subclassing to provide a response mixin. |
| 202 | + """ |
| 203 | + |
| 204 | + async def get(self, request, *args, **kwargs): |
| 205 | + self.object = await self.get_object() |
| 206 | + return await super().get(request, *args, **kwargs) |
| 207 | + |
| 208 | + async def post(self, request, *args, **kwargs): |
| 209 | + self.object = await self.get_object() |
| 210 | + return await super().post(request, *args, **kwargs) |
| 211 | + |
| 212 | + |
| 213 | +class AsyncUpdateView(SingleObjectTemplateResponseMixin, AsyncBaseUpdateView): |
| 214 | + """View for updating an object, with a response rendered by a template.""" |
| 215 | + |
| 216 | + template_name_suffix = "_form" |
| 217 | + |
| 218 | + |
| 219 | +class AsyncDeletionMixin: |
| 220 | + """Provide the ability to delete objects.""" |
| 221 | + |
| 222 | + success_url = None |
| 223 | + |
| 224 | + async def delete(self, request, *args, **kwargs): |
| 225 | + """ |
| 226 | + Call the delete() method on the fetched object and then redirect to the |
| 227 | + success URL. |
| 228 | + """ |
| 229 | + self.object = await self.get_object() |
| 230 | + success_url = self.get_success_url() |
| 231 | + await self.object.adelete() |
| 232 | + return HttpResponseRedirect(success_url) |
| 233 | + |
| 234 | + # Add support for browsers which only accept GET and POST for now. |
| 235 | + async def post(self, request, *args, **kwargs): |
| 236 | + return await self.delete(request, *args, **kwargs) |
| 237 | + |
| 238 | + def get_success_url(self): |
| 239 | + if self.success_url: |
| 240 | + return self.success_url.format(**self.object.__dict__) |
| 241 | + else: |
| 242 | + raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.") |
| 243 | + |
| 244 | + |
| 245 | +class AsyncBaseDeleteView(AsyncDeletionMixin, AsyncFormView, AsyncBaseDetailView): |
| 246 | + """ |
| 247 | + Base view for deleting an object. |
| 248 | +
|
| 249 | + This requires subclassing to provide a response mixin. |
| 250 | + """ |
| 251 | + |
| 252 | + form_class = Form |
| 253 | + |
| 254 | + async def post(self, request, *args, **kwargs): |
| 255 | + # Set self.object before the usual form processing flow. |
| 256 | + # Inlined because having DeletionMixin as the first base, for |
| 257 | + # get_success_url(), makes leveraging super() with ProcessFormView |
| 258 | + # overly complex. |
| 259 | + self.object = await self.get_object() |
| 260 | + form = await self.get_form() |
| 261 | + if form.is_valid(): |
| 262 | + return await self.form_valid(form) |
| 263 | + else: |
| 264 | + return await self.form_invalid(form) |
| 265 | + |
| 266 | + async def form_valid(self, form): |
| 267 | + success_url = self.get_success_url() |
| 268 | + await self.object.adelete() |
| 269 | + return HttpResponseRedirect(success_url) |
| 270 | + |
| 271 | + |
| 272 | +class AsyncDeleteView(SingleObjectTemplateResponseMixin, AsyncBaseDeleteView): |
| 273 | + """ |
| 274 | + View for deleting an object retrieved with self.get_object(), with a |
| 275 | + response rendered by a template. |
| 276 | + """ |
| 277 | + |
| 278 | + template_name_suffix = "_confirm_delete" |
0 commit comments