Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Data Graham
Dec 28, 2009

📈📊🍪😋



Do you have access to the server's outgoing mail logs?

Adbot
ADBOT LOVES YOU

Data Graham
Dec 28, 2009

📈📊🍪😋



Storgar posted:

I'm having trouble making connections about Django's class based views. I'm lazy and I can't find an example of a Django edit view class.

I want to make a class based view that contains functions to create (post) and delete model instances. (First of all, is this best practice? What do people normally do for this sort of thing?) How can I view the automatic urls generated by this class if I use as_view()? I am fuzzy on how I actually call the class methods from an html form.

Where are you reading that class-based views give you automatically generated URLs? That's the first I'm hearing of such a thing. To my knowledge you have to list all your URLs in urls.py.

But yeah, it's perfectly good practice to do like this:

code:
class MyObject(APIView):

    def get(self, request, format=None):
        ....
        return Response({})

    def post(self, request, format=None):
        ....
        return Response({})

    def delete(self, request, format=None):
        ....
        return Response({})

Then hook up urls.py like this:

code:
url(r'^myobject/$', foo.views.MyObject.as_view()),
And that one URL endpoint will handle all the methods you define functions for. You can fiddle with the URL pattern to handle object IDs and the like.

Data Graham
Dec 28, 2009

📈📊🍪😋



Nah, it's all the same URL. The only difference is in the HTTP method you use to make the call.

If it's a bare HTML form, you'll have a <form method="POST"> attribute, and that's where you would put DELETE if it's a delete request. Depending on what method you use, Django will route it to the right method call in the class.

Same if you're using jQuery; you'd use $.post() or $.delete() depending. It all goes to the same endpoint.

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah, that's why I was suggesting jQuery. (It's been a long time since I used a normal HTML form; I'd forgotten whether the GET/POST thing was in the spec or a limitation in older browsers.)

But if you're using the full REST method suite, I'd think you'd want to be using AJAX for your interactions.



E: To be clear, if you are limited to using plain HTML forms, you probably aren't going to be able to take full advantage of class-based views. You'll have to implement your DELETE method as a separate class and call it with a myobject/delete URL posting to MyObjectDelete.as_view() or the like.

At that point your view structure will be pretty ugly and hybridized, so you might have to just bite the bullet and abandon class-based views, and do straight method-based views for each of your GET and POST and DELETE requests.

Data Graham fucked around with this message at 12:04 on Apr 15, 2015

Data Graham
Dec 28, 2009

📈📊🍪😋



rest_framework question.

Is there some reason why the REST API should be dog-slow compared to just creating a basic view method and outputting the JSON dump of the object (or a serializer'd version of it)?

I've inherited a fully developed Django system and I'm trying to find some way of profiling this, which takes upwards of 10 seconds to query a single object (i.e. with the /widgets/256/ URL form):

code:
urls.py:

...
router.register(r'widgets', api.WidgetViewSet)
...

api.py:

from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from rest_framework import permissions
from rest_framework_extensions.decorators import action
from rest_framework_extensions.cache.mixins import ListCacheResponseMixin as CacheMixin
from rest_framework_extensions.key_constructor.constructors import KeyConstructor
from rest_framework_extensions.key_constructor import bits
from rest_framework_extensions.cache.decorators import cache_response

class WidgetViewSet(viewsets.ModelViewSet):
    queryset = models.Widget.objects.filter(hidden=False).order_by('name')
    serializer_class = serializers.WidgetSerializer
    filter_fields = models.Widget._meta.get_all_field_names()
If I throw logging into that class, all the lag time occurs after the class attributes are all set (i.e. if I log after the "filter_fields" line, it appears almost instantly, but then the browser doesn't render the result for another 8-10 seconds).

If instead I do this:

code:
views.py:

def widget_test(request):

    w = Widget.objects.get(pk=256)

    widget = {
        'id': w.id,
        'name': w.name,
        'subname': w.subname,
        ...
    }

    return HttpResponse(json.dumps(widget))
...Then the response comes back almost immediately.

The Occam's Razor solution to this would, of course, be to just make my own views like the above, but the REST API is fully fleshed out with dozens of endpoints and serializers and so on, all using the built-in browseable interface. (I've already eliminated the serializers as being the issue.) I don't want to throw away what appears to be a system built the "right" way in favor of my kludgey but demonstrably much much faster one. I'd love to know if this situation rings any bells with anyone. Thanks...

Data Graham
Dec 28, 2009

📈📊🍪😋



Hed posted:

Use django-debug-toolbar with something approximating real data on your dev/test server

+1 this, thanks.

Turns out the DRF is doing a complete separate query for every model that has a ForeignKey relation to the Widget model (e.g. WidgetComponent, of which there are an assload of records and the slowness is purely from volume). Of course I'm not doing that for my own homegrown endpoint because I'm not making any calls to widgetcomponent_set or anything, and so it's super fast.

Is there a way to make the DRF not make those queries? I've tried select_related, but it doesn't seem to have any effect (I kinda want the opposite).

Data Graham
Dec 28, 2009

📈📊🍪😋



Well, like I said, I tried adding select_related('widgetcomponent') to the "queryset =" in the API view, but it didn't make any difference; it still made the separate query for all WidgetComponents (completely unconstrained), right before it selects the Widget for the ID I want. From the toolbar:

code:
SELECT ••• FROM `django_session` WHERE (`django_session`.`session_key` = '...' AND `django_session`.`expire_date` > '2015-06-04 18:28:38' )
SELECT ••• FROM `catalog_widgetcomponent`
SELECT ••• FROM `catalog_widget` WHERE (`catalog_widget`.`hidden` = 0 AND `catalog_widget`.`id` = 1234 )
Am I doing it right, though? I can pass totally invalid arguments to select_related and it doesn't seem to care. Is this the right syntax? WidgetComponent has a widget attribute which is a ForeignKey to Widget.

code:
    queryset = models.Widget.objects.select_related('widgetcomponent').filter(hidden=False).order_by('name')

    queryset = models.Widget.objects.select_related('widgetcomponentblah').filter(hidden=False).order_by('name')
And again, it doesn't do any of those queries for widgetcomponent if I just fetch the object directly like in my views.py above.


E: select_related seems to be for going the other direction, i.e. if I were looking up WidgetComponents and wanted to join the related Widgets into the query. For going the direction I want, i.e. selecting Widgets and trying to avoid looking up all WidgetComponents, the docs suggest that that only works with OneToOneFields with a related_name defined.


E2: Okay, adding related_name='+' to the ForeignKey field on the WidgetComponent model did the trick. Now I just hope nothing else was depending on that backward relation being there.

Data Graham fucked around with this message at 19:46 on Jun 4, 2015

Data Graham
Dec 28, 2009

📈📊🍪😋



They are.

Data Graham
Dec 28, 2009

📈📊🍪😋



Ahz posted:

I've been using Django for a couple years now and every now and then I try to ease myself into the convenience of modelforms, modelserializers, class based views etc. but every time I do, I find when I want to do something interesting or outside the box, I hit a wall and go into an override frenzy where I should have just used basic forms or serializers and function based views where I have total control.

Phew, I thought I was the only one.

The last couple of Django jobs, I've inherited systems that had been thoroughly and carefully built by-the-book, with serializers, viewsets, on-model methods, the whole nine yards. But I always end up spending ten times as much time unraveling them and figuring out where to make simple logic tweaks as I would have if I'd just done it the way I did three jobs ago when none of us knew what we were doing and we just made a pile of monolithic function-based view.py's. It might have been ugly and repetitive and low in code reuse, but drat if we weren't cranking out new features daily. And drat if the guy they hired to pick up after I left wasn't up and running in a matter of days.

Never mind how in some of these more recent jobs I've found myself confronting viewset-generated API endpoints that spit out hundreds of times more data than is necessary, with programmatically generated queries that take many seconds to complete and then many more seconds just to transport and serialize before it even starts spewing to the browser. All conscientious and by-the-book, mind you. But it's not just that it was unoptimized, it's that the system never seemed to give the original devs any indication that they should optimize it.

Data Graham
Dec 28, 2009

📈📊🍪😋



Can't you do ~Q(next=F('id') ?

Data Graham
Dec 28, 2009

📈📊🍪😋



God dammit. It's those kinds of things that made me want to dig in my heels on modern tools and resist Java.

Data Graham
Dec 28, 2009

📈📊🍪😋



What's the best-practice way of handling sensitive data strings in server configs (like database passwords) that you don't want to publish to version control? I want to store my secrets a) securely, b) privately, and c) only in a single location, such that both the web server and manage.py can use them.

Talking in particular of Apache/wsgi, though I imagine pretty much every server would have similar issues.

I thought I was onto something by using a db.cnf file in DATABASES['default']['OPTIONS']['read_default_file'] -- just put the password in that and chown it 600 -- but then Apache can't read it.

I had to go back to my previous best solution, which is to store sensitive strings in the Apache configuration itself (chmod 600), and pass them in via wsgi.py hackery:

httpd-vhosts.conf
code:
    SetEnv SECRET_KEY (u+6(^0^o!317$!l33aweG23$)au=fqm-l3a)*eg(!!y2f)k#is
    SetEnv DB_PASS BlahPassword
wsgi.py
code:
#application = get_wsgi_application()

env_variables_to_pass = ['SECRET_KEY', 'DB_PASS']
def application(environ, start_response):
    for var in env_variables_to_pass:
        os.environ[var] = environ.get(var, '')
    return get_wsgi_application()(environ, start_response)
And then in settings.py I can pull the strings with os.environ['DB_PASS'] and so on.

But the downside to this is that while it sets the environment variables properly for wsgi, it doesn't help me with manage.py. I can put an export DB_PASS="BlahPassword" into my virtualenv activate script, but that means I'm keeping the pw in two places, which sucks.

I thought of parsing the httpd-vhosts.conf in the activate script, but a) it's bash and b) even the python options for parsing Apache config files are either "use some dude's script from 2008" or "do it myself".

I've now been through at least three recent jobs at high-flying tech companies where the codebase either doesn't give two shits about storing the passwords directly in settings.py, or else they apparently run totally password-less and just rely on firewall rules for security or something.

This can't really be the state of things in tyool 2015, can it?

Data Graham fucked around with this message at 16:46 on Dec 7, 2015

Data Graham
Dec 28, 2009

📈📊🍪😋



porksmash posted:

You can just make a separate file with your sensitive stuff and import * it in settings.py. Don't commit that file to your repo and you're good.

Unfortunately that doesn't work if it's owned by root and chmod 600.

I can chown it www or chmod it 644 so Apache can see it, but then it's also visible to any other programs on the server that want to try to read it.

I suppose one answer to this is "don't run a server with ~users and critical data at the same time", and maybe that's a fair stance to take nowadays, but I feel like that can't actually be the only right answer in the world of unix permissions.

Data Graham
Dec 28, 2009

📈📊🍪😋



Thermopyle posted:

I think I'm just missing something here, because my question is...why does your web server need to know your database connection information?

I mean, I usually just set the enviornment variables on the server and read them in my django settings and that works...

Where do you set them?


E: It's not that the web server needs to see the info per se, it's that wsgi is being executed as www, and it needs that info to connect. It has to come from somewhere that's either accessible to www or passed down to it from the web server itself (which is launched by root), and the former seems like a non-starter, so I'm back to the latter.

Data Graham fucked around with this message at 20:43 on Dec 7, 2015

Data Graham
Dec 28, 2009

📈📊🍪😋



Not bad. Proxying sounds pretty solid. It might be overkill for the kinds of things I'm doing right now, but I'll bear it in mind for the next time I get into it. Thanks!

Data Graham
Dec 28, 2009

📈📊🍪😋



Has anyone successfully gotten django-two-factor-auth working with the Django admin?

I've followed the setup instructions in the docs, particularly this part: http://django-two-factor-auth.readthedocs.org/en/stable/implementing.html#admin-site

And I've got this in my urls.py:

code:
otp_admin_site = AdminSiteOTPRequired()

urlpatterns = [
    url(r'', include('two_factor.urls', 'two_factor')),
    url(r'^admin/', include(otp_admin_site.urls)),
    ...
]
And it logs me in fine, using two-factor auth the way it's supposed to. But then, instead of the usual list of registered ModelAdmin models to interact with, it tells me "You don't have permission to edit anything".

Seems like the models aren't getting registered? Any ideas on how to even debug this?

Data Graham
Dec 28, 2009

📈📊🍪😋



Never mind the above, incidentally. Some more loving around and

code:
from django.contrib.auth.models import User, Group, Permission
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from two_factor.admin import AdminSiteOTPRequiredMixin, admin

class AdminSiteOTPRequired(AdminSiteOTPRequiredMixin, AdminSite):
    """
    AdminSite enforcing OTP verified staff users.
    """
    pass

otp_admin_site = AdminSiteOTPRequired()

otp_admin_site.register(User, UserAdmin)
otp_admin_site.register(Group, GroupAdmin)
otp_admin_site.register(Permission)

@admin.register(Widget, site=otp_admin_site)
class WidgetAdmin(admin.ModelAdmin):
     ...
You have to register the auth ones manually as well as any you might want to add yourself, and making the AdminSite subclass with the AdminSiteOTPRequiredMixin allows you to .register() to it directly or call the decorator on two_factor.admin instead of the built-in one.

(Note that AdminSiteOTPRequired already exists in two_factor.admin anyway so I could have imported it from there; but I also wanted to use an existing AdminSite subclass to allow django.contrib.gis.admin.GeoModelAdmin)

Just a documentation thing if anything.

Data Graham fucked around with this message at 23:26 on Jan 27, 2016

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah, that's pretty much what you do. An extension model with a OneToOneField that extends the base User class, and then you'll have those fields whenever you have a request.user object.

Data Graham
Dec 28, 2009

📈📊🍪😋



The django-cron guy finally fixed that 1.10 deprecation warning, wooo!

Data Graham
Dec 28, 2009

📈📊🍪😋



That's definitely a python question and not Django.

But my guess is that it's deleting that directory as part of the cleanup. Can you watch /tmp while the install is going and see if something is getting created then?

e: or that

Data Graham
Dec 28, 2009

📈📊🍪😋



I mean if you think Django docs are bad I dare you to even try to make your way through Javadocs :v:

Data Graham
Dec 28, 2009

📈📊🍪😋



It's in case your primary key is called something other (longer) than "id".

Don't know this for sure, but it's also worded to suggest that what it's really a shortcut for is Question.objects.get(id__exact=1), which might have been standard usage earlier than "id=1".

Not a great piece of documentation there.

Data Graham
Dec 28, 2009

📈📊🍪😋



Your "about" is just pulling the first record from the About_Author model. It's not a thing you can loop over.

What you want is probably this:

code:
links = About_Author_Link.objects.filter(about=<some_author_instance>) # Assuming you want to iterate through all the links for a given author
code:
{% for link in links %}
	<h1>{{link.url_title}}</h1>
{% endfor %}
A couple of notes:

Object naming in Django wants to use names like AboutAuthor and AboutAuthorLink, not About_Author and About_Author_Link. It's kind of opinionated about underscores. If you use them in model names you'll end up with some confusing-rear end database table names.

For clarity on what the models are for, you might want to try to keep their names more concise and specific. So if it's an author, just call it Author. And if the link objects are for social media outlets, something like SocialMedia might be better. Or MediaLink if you want it to be more generic. No reason to mention Author in the model name.

That way your ForeignKey field can refer more clearly to the model it's referencing. So your SocialMedia object will have an "author" field, not an "about" field (which feels like a misleading name). Then your code can convey its meaning a lot more semantically, like

code:
social_media_links = SocialMedia.objects.filter(author=<some_author_instance>)

for link in social_media_links:
    print social_media_link.author.title

Data Graham
Dec 28, 2009

📈📊🍪😋



If you're making a view-and-edit interface for end users, you kinda just have to make your peace with the fact that you have to explicitly know what attributes your model has and code them all into the HTML. Trying to programmatically dump model fields in a way that sorts nicely and handles different field types properly (e.g. dates) is more trouble than it's worth.

If you literally just want a dump of the object for debugging purposes, you can echo the whole thing with {{ object_name }}, or you can convert the whole model instance to an array in the view function like this and then iterate over it in the template.

Data Graham
Dec 28, 2009

📈📊🍪😋



./manage.py collectstatic

Data Graham
Dec 28, 2009

📈📊🍪😋



What template is this in? One you wrote yourself, or one that's part of some package?

Data Graham
Dec 28, 2009

📈📊🍪😋



So... I don't get it then. Don't you have control over your HTML code? Why is the img src= not up to you?

Data Graham
Dec 28, 2009

📈📊🍪😋



What does your template code look like? I'm not picturing what part Django is playing in your HTML structure.

Unless you're using {% static %} tags, but I figured collectstatic would have dealt with that.

Data Graham
Dec 28, 2009

📈📊🍪😋



Aha, I didn't realize your images were themselves variables/data. I thought this was an issue with static files you'd uploaded.

Glad to hear you found it.

Data Graham
Dec 28, 2009

📈📊🍪😋



Because your settings module will probably end up in source control, and you don't want to keep things like passwords and secret keys in source control.

Data Graham
Dec 28, 2009

📈📊🍪😋



Has anyone fought through this one?

I'm using Django with MySQL; my tables are all utf8mb4 with collation utf8mb4_general_ci. I'm able to save four-byte Unicode strings (i.e. 💩) into the TextFields of my models through the admin just fine; but CharFields give me an error:

code:
OperationalError: (1366, "Incorrect string value: '\\xF0\\x9F\\x92\\xA9' for column 'object_repr' at row 1")
What's weird is that I can paste 💩 directly into the database field via a GUI like Sequel Pro and it takes it just fine, whether it's a VARCHAR (i.e. CharField) or a TEXT (i.e. TextField) field. In other words MySQL itself doesn't seem to care. But Django does.

This happens with CharFields with max_length set to 255 or 50.

I've read this https://docs.djangoproject.com/en/1.10/ref/databases/#mysql-collation and this http://blog.manbolo.com/2014/03/31/using-emojis-in-django-model-fields, but nothing seems to acknowledge that there's a difference in behavior between CharField and TextField, or that it's something in Django that's breaking because the MySQL client takes 4-byte strings fine.

Is there some trick to making my CharFields use the same character encoding that TextFields use?




E: AAHH gently caress. I poked through the DB for "object_repr" columns, and of course there's one in the django_admin_log table, and of course it's set to latin1 :doh:

Data Graham fucked around with this message at 05:44 on Nov 2, 2016

Data Graham
Dec 28, 2009

📈📊🍪😋



Thermopyle posted:

Has anyone else found that over their Django career they migrated back to function-based views from class-based views?

I used to use CBV's quite extensively, but I've found that I just really value the explicit nature of FBV's and that they seem to better mesh with the "explicit is better than implicit" Python mantra.

It's not that I really find CBV's to be all that bad, I've just slowly grown into this mindset where I find them unnecessary.

drat I'm glad you said this.

I always feel like I'm doing something dirty by wiring up views one-to-one with URLs and building explicit dicts for my return objects, but six months later if I have to tinker with something it makes it a billion times easier. And what if your app does more than basic CRUD, where oh I dunno you have like three or four different kinds of mutate actions that operate on an object (or several different objects that aren't all that separable) instead of just one obvious "update"? CBVs seem like a case of designing around the happy path and then trimming out all the flexibility to do non-happy-path things.

I don't think anyone's first exposure to DRF serializers and ViewsSets should be when they have to reverse-engineer someone else's beautiful perfect CRUD API to jimmy in a new piece of functionality that doesn't fit quite so neatly into that pattern, meaning they have to rip the whole thing apart to expose all the nuts and bolts they need.

Data Graham
Dec 28, 2009

📈📊🍪😋



Got a rather interesting problem here.

I got this model, see. I want the id to be a BigAutoField, and I want it to be a randomly generated integer, not sequential. Purpose being that I don't want it to be easily guessable or predictable. And because I'm going to be using a Base## method to shorten it for URL exposure, I don't want the ID to be a long or alphanumeric thing like a UUID.

So I'm doing this:

code:
id = models.BigAutoField(primary_key=True, default=generate_pk)

def generate_pk():
    return random.randrange(2147483647) # just to keep it to 32 bit for now
And this is fine for generating the random key I need. However, what do I do when I inevitably get collisions? I figure I would like to override the save() method on the model, and trap IntegrityError and regenerate the ID in that case (perhaps in a while loop until it finds an empty slot); but I'm having trouble seeing how or where to do that.

If I do something like:

code:
    def save(self, *args, **kwargs):
        try:
            super(MyModel, self).save(*args, **kwargs)
        except:
            self.pk = generate_pk()
            super(MyModel, self).save(*args, **kwargs)
—Then it gives me a TransactionManagementError: "An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.", coming from deep in the db backend.

I feel like I'm barking up the wrong tree here. Any ideas on what I ought to be doing?



Edit: looks like this might get me past it; leaving it here in case it helps anybody:

http://stackoverflow.com/questions/21458387/transactionmanagementerror-you-cant-execute-queries-until-the-end-of-the-atom

Data Graham fucked around with this message at 06:31 on Jan 2, 2017

Data Graham
Dec 28, 2009

📈📊🍪😋



Add a success: callback function in your ajax call, and do a document.location.reload() in it.

Data Graham
Dec 28, 2009

📈📊🍪😋



Hey guys. I'm getting myself embroiled in a bit of a philosophical war with a business associate over whether I can use Django for production apps, or (his preference) that we use Java for everything.

His objections to Django are that it's a "toy", that it's hardly better than WordPress from an architectural standpoint, and (probably the biggest sticking point right now) that there's no way to protect secret strings like the database password.

In his ideal world there's no way for a local user on the server to be able to extract those secret strings from the web app, because they're compiled into an executable binary or archive. In Django you have to have your secret strings either sitting in plaintext in the settings.py file, or imported from some other file that's readable by the www user anyway, which means anyone who's able to hijack a login shell of a user who has access to those files would get the keys to the kingdom.

I know this is kind of a wacky irrational position to take and that best practices are such that basically if anyone gets local shell access you should consider your system totally compromised, but that's not good enough for him. I want to see if there's any possible way I can harden a Django/Apache/mod_wsgi installation to his satisfaction.

The best solution I've been able to come up with has been to set the secret strings in the httpd.conf (in the vhost), setting them as environment variables with SetEnv statements, and then importing them into the application with a custom call to get_wsgi_application() in wsgi.py. Theoretically that was good because you could then make your httpd.conf readable only by root and it would pass the variables at startup and be inaccessible to no non-root users; but turns out that's not good enough either because he doesn't want to run apache as root either, for security reasons. I'm back to having the strings in a file readable by the www user, which there doesn't seem to be a way around.

Has anyone been able to figure out an ingenious way around this? I would very very very much like to continue using Django for our projects and not have to use ColdFusion (which he loves because all the sensitive strings are encrypted at the app server level and a local user has no access to it), or some JSP platform which I'm not sure why he thinks would be any more secure because to my knowledge all the JSP frameworks involve storing passwords and such in cleartext just like in Django. I'd rather not fall back on that argument either; I'd want to know if there's some way of locking down Django itself.

Data Graham
Dec 28, 2009

📈📊🍪😋



epalm posted:

I get the feeling that, even if you convince your associate of a solution to the secret-hiding problem, he/she is just going to find more "reasons" to use the thing they've already decided they want to use.

No doubt.

It's been a long slog, just getting to the point where I'm able to get Django a fair hearing. I'm sure the only real answer is "just keep having a good track record for another decade or two".

(He honestly believes in security through obscurity, is the thing. If an encryption routine is hidden in an imported script fragment called "snrbpt.cfm" instead of done inline in the main file, that to him is enough of a pain in the rear end to a potential intruder for him to get bored and give up or something.)

I'll see if Vault can do anything for me, thanks.

Data Graham fucked around with this message at 00:02 on Mar 5, 2017

Data Graham
Dec 28, 2009

📈📊🍪😋



Sounds to me like an excellent way to trick yourself into thinking client-side validation is all you need.

Data Graham
Dec 28, 2009

📈📊🍪😋



code:
<div class="ui celled relaxed selection list">
{% for item in food %}
    <div class="item">
        <div class="header">{{ item.name }}</div>
        <div class="ui horizontal list">
            <div class="item">
                <div>Calories: {{ item.calories }}</div>
            </div>
            <div class="item">
                <div>Protien: {{ item.protien }}</div>
            </div>
            <div class="item">
                <div>Fat: {{ item.fat }}</div>
            </div>
            <div class="item">
                <div>Carbs: {{ item.carbs }}</div>
            </div>
        </div>
    </div>
{% endfor %}
</div>
?

Data Graham
Dec 28, 2009

📈📊🍪😋



Forms are like the last item on my "Django things to make friends with" list.

So much form handling logic these days wants to be ajaxy, or like you say, do more than basic REST/CRUD stuff. But in those cases where what I want to do does fit nicely with the classical pattern, it can be a joy. I love the idea of all my validation errors being returned in a nice marshaled way so I can style them how I want, and the back-end form_valid method being something I can just trust to only get fired when I want it to. And then there's all the niceties of localization.

Though... when you say "make your own in HTML/JS", you don't mean you're doing all your form validation logic in the front-end, do you? :raise:

One of Django forms' biggest benefits is that it makes it a low bar to doing your logic in the back-end and keeping you from being tempted to move it into JS, with all the security issues that implies. When I struggle with whether to use Django forms, it's "as opposed to building my own form handling logic in views" versus "as opposed to using a front-end solution".

Apologies if I'm jumping to conclusions.

Adbot
ADBOT LOVES YOU

Data Graham
Dec 28, 2009

📈📊🍪😋



DRF and Django Forms don't really coexist super well. You can build forms in the DRF-endorsed way, but it's all built on its own serializers and doesn't give you validators like the Django native forms do.

You can try to stitch them together but it's kind of unsatisfying: https://ejosh.co/de/2014/02/django-rest-framework-and-forms/

For user-facing stuff I usually stick with regular Form views, and keep my DRF views for building API endpoints.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply