Sure most CRUD applications work perfectly fine using WSGI, but for anyone using other protocols like WS or MQTT in their app this is kind of a big deal.
Sure most CRUD applications work perfectly fine using WSGI, but for anyone using other protocols like WS or MQTT in their app this is kind of a big deal.
You typically do Django + REST because you are already comfortable with Django or because you were already using it, although I could argue, you could consider making your API project stand alone and using CherryPy or even FastAPI for a much nicer experience. The downside there being you wouldn't be using Django's ORM. I really do wish Django's ORM would be spun off into a stand alone project that Django then imports, so anyone else can use it in other non-django specific projects.
It basically boils down to rejecting the folder structure that django-admin sets up for you, importing stuff yourself and doing some basic initialisation/configuration.
Once you do that, django kinda somehow behaves like a micro-framework, with the significant difference that you can import and use the advanced features if you want/need to.
https://github.com/planetfederal/registry/blob/149a2b958dd05...
you start with "i will do in flask because it's easier". then you need to add authorization/authentication. and then templating, ORM, maybe some RESTful flask library to make endpoints a bit easier... and now you have django, but in a different way.
You can then within minutes return JSON coming from your data model by also adding an additional decorator to make it render JSON output.
If returning data directly from managed ORM objects, you will need to serialize it, but you can easily build an API without doing that and just return a dict.
If you are writing view code in DRF, you are probably doing it wrong.
Even things as simple as adding logging to calls on certain end points will require you do provide your own view method (which might then call the mixin’s provided method).
It makes sense as backend for a native iOS/Android app, and if you already have that REST endpoint then it can make sense to re-use it for the web-version of your app.
But if you're not doing an iOS/Android app (most websites?), then I generally agree it's a lot more work compared to form-based / server-side-templates (though sometimes can give a _slightly_ better user experience, _if_ done correctly.)
HTMX seems to be growing as a "REST endpoint" alternative, but again not as useful if you're also doing a native iOS/Android app.
A well-implemented REST app is pretty nice, business logic divorced from all UI and API lends itself nicely as a comfortable and maintainable programming environment. More often than not, being RESTful from the get-go tends to have positive returns down the line.
This really isn't true. Mobile apps are far more expensive to develop (everything is doubled, you're dealing with periodic forced updates outside of your development schedule, etc.) and there are a ton of apps which don't need anything you can't do in a browser.
One of the earliest things to do on a project is agreeing on what level of complexity makes sense for you. If your project doesn't have a known hard requirement for mobile apps and correspondingly large team sizes, a classic Django app is likely to let you iterate an order of magnitude faster at lower cost overall.
When you need to wire up custom serializers per model (eg specifying subsets of fields or making some read-only) and wire up non-CRUD actions then I think you can fall down a slippery slope where you write as much (or more) code than if you just used say marshmallow and flask to manually write your API.
Also you get the Django model admin for free, so for internal services you have a nice CRUD admin for operators.
I think it’s a great tool for accelerating your first 100-200kloc of API code. Beyond that it can start to creak at the seams depending on your usecase. (I’d make the same assessment about Django itself FWIW).
Great work Django team!
https://docs.djangoproject.com/en/4.1/releases/4.1/#asynchro... :
`QuerySet` now provides an asynchronous interface for all data access operations. These are named as-per the existing synchronous operations but with an `a` prefix, for example `acreate()`, `aget()`, and so on.
> The new interface allows you to write asynchronous code without needing to wrap ORM operations in `sync_to_async()`:
async for author in Author.objects.filter(name__startswith="A"):
book = await author.books.afirst()
> Note that, at this stage, the underlying database operations remain synchronous, with contributions ongoing to push asynchronous support down into the SQL compiler, and integrate asynchronous database drivers. The new asynchronous queryset interface currently encapsulates the necessary sync_to_async() operations for you, and will allow your code to take advantage of developments in the ORM’s asynchronous support as it evolves. […] See Asynchronous queries for details and limitations.## Asynchronous handlers for class-based views
> View subclasses may now define async HTTP method handlers:
import asyncio
from django.http import HttpResponse
from django.views import View
class AsyncView(View):
async def get(self, request, *args, **kwargs):
# Perform view logic using await.
await asyncio.sleep(1)
return HttpResponse("Hello async world!")Basically every function call that does db-queries needs an "a"-prefixed version. aget(), acreate(), aget_or_create(), acount(), aexists(), aiterator(), __aiter__, etc. And in future versions they'll work on the lower level, undocumented api, like _afetch_all(), aprefetch_related_objects(), compiler.aexecute_sql(), etc.
Eventually you'll probably need to switch database drivers to something that actually supports async.
entries = Entry.objects.filter(
category="python"
).order_by("-created")[:10]
Then pass that to a template which does this: {% for entry in entries %}...
Django doesn't actually execute the SQL query until the template starts looping through it.Async template rendering becomes necessary if you want the templates to be able to execute async SQL queries in this way.
Jinja has this feature already with the enable_async=True setting - I wrote a tiny bit about that in https://til.simonwillison.net/sqlite/related-content
With async, we can use async HTTP libraries and scale these WAY better.
Async is beneficial when you make multiple blocking (http) request to a resource at the same time and later fold that into one response. Parallel stuff. Or when you are forced to run a single thread. Or when you are memory bound.
Reality is that most requests depend on previous requests quite often. In the latter case there is no benefit in terms of speed for the user.
I know this is unpopular opinion though :-)
Other than that, it has benefits too! :-)
Note that, at this stage, the underlying database operations remain synchronous, with contributions ongoing to push asynchronous support down into the SQL compiler, and integrate asynchronous database drivers....
https://docs.djangoproject.com/en/4.1/releases/4.1/#asynchro...
Couldn't it be the inverse? I.e. your inexeperience with async code in other languages, and not understanding it fully, translating into "new thing aversion"?
Unless async is the default python, it will always be an after thought and introduce needless complexity when working on large projects that require a lot of external libs.
def slow_sync_view(request):
# these requests won't be executed in parallel;
# async version could eliminate this extra latency
foo = requests.get('https://www.google.com/humans.txt').text
bar = requests.get('https://checkip.amazonaws.com').text
return HttpResponse(f'{foo}\n{bar}')You would have to queue one task for each request in the event loop and then await for them both to gain some parallelism in the I/O section of the code.
https://docs.python.org/3/library/concurrent.futures.html#co...
It can be hard to determine if something is doing something blocking and if it is, it is hard to debug. Especially in python world which, unlike javascript, was not async from the start.
That just means you can only handle 20 concurrent requests before performance drops off a cliff. If the third-party service you are talking to is slow, then you’ll just end up with 20 workers all waiting for the service to respond, while other requests pile up. With async, those workers could still be handling other requests. Adding more workers because you are blocking on i/o works for low traffic services, not for anything remotely busy.
I was just saying that async quite often is not of much help and just complicates things. Of course it has its use! Your case is a great example of converting a django view into an async view.
Yes.
That just means in very bad cases, you can only handle 1 "concurrent request" before performance drops off a cliff. If the third-party service you are talking to is that slow, then you’ll just end up with bufferbloat (high latency in hidden queues) waiting for the service to respond, requests piling up.
With async, unless you know what you're doing and handle back pressure, work pile up even worse, the service stops working and you get 0 throughput instead.
With async instead you would still be able to handle thousands of rps.
Yes, if you do WebSockets, async really is a must if you don't want to have one thread per active connection. Each thread takes 8mb of virtual memory, not sure how much actual memory.
It's also nice for a backend that's doing a lot of proxying apis to another backend.