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

📈📊🍪😋



Thermopyle posted:

I'm sure most of you know about Classy Class Based Views, the site that helps you understand how to use CBV's by giving a clearer picture of the methods and inheritance structure.

I didn't, but I'm sure glad I do now!

Adbot
ADBOT LOVES YOU

Data Graham
Dec 28, 2009

📈📊🍪😋



Especially since we all now have your IP for as long as your lease lasts :nsa:

Data Graham
Dec 28, 2009

📈📊🍪😋



Anybody know what the rationale is for the Django admin not creating links to related objects in the object list views?

It just lists them by their __unicode__() return strings, but it sure seems like an obvious feature would be to allow you to navigate from one object to another directly if it knows how they're related. Even most database GUIs do that to some degree.

Data Graham
Dec 28, 2009

📈📊🍪😋



Something that I've only fairly recently come to make friends with is the notion of putting your derived data into @property methods in your models.

I used to chafe under the strictness of Django's templating logic, but once I realized the benefits of pushing as much logic as possible as far back toward the model as possible, a lot of what I had been trying to do at the template level simply stopped being necessary. Now those properties are reusable too.

Data Graham
Dec 28, 2009

📈📊🍪😋



Thermopyle posted:

I don't have time to type a lot right now, but one aspect of the purpose of putting it on the model or other utility modules is that you can't keep your code more generic by having it in your view.

I mean, if, as part of your view, you have code that does x, y, and z, how are you going to use that code elsewhere? What if you want a view later that wants x, y, and z along with other stuff?

Or (for a very common pattern), what if you want a view that feeds a template for a web app, and then also a Django REST Framework view creating an API for a mobile app? Both need to have the same data properties/methods, but only if you put that code in the model will you be able to avoid writing that logic twice.

E: For that matter DRF won't even help you unless your logic is in the model anyway.

Data Graham
Dec 28, 2009

📈📊🍪😋



Is there a way to force a reversed URL to contain a slash after an optional kwarg in the pattern?

I'm doing this:

code:
    url(r'^account/work/(?P<page>[a-z]+)?/?$', login_required(accounts_views.WorkView.as_view()), name='account-work'),
So I want these reverses to happen:

code:
account-work                /account/work/
account-work page=first     /account/work/first/
account-work page=second    /account/work/second/
But with the trailing slash in the pattern like that, as an optional, it never appends it in the reverse; I get like '/account/work/first'.

If I make the slash non-optional, then 'account-work' reverses to '/account/work//', and I don't want that.

Is there a better way to do this?

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah, that's my problem. I want it to always have the slash, but I can't seem to do that without the bare "work" URL getting an extra slash, /account/work//.

Data Graham
Dec 28, 2009

📈📊🍪😋



No dice; says 'account-work' with no arguments doesn't match any patterns. 'account-work' with an arg specified works though.

Data Graham
Dec 28, 2009

📈📊🍪😋



MonkeyMaker posted:

You can have more than one route that points to the same view.

code:
url(r'^account/work/$', login_required(accounts_views.WorkView.as_view()), name='account-work'),
url(r'^account/work/(?P<page>[a-z]+)/?$', login_required(accounts_views.WorkView.as_view()), name='account-work-page'),
Not super-elegant, I guess. Pumpkin Pirate's solution might work, too. I'm not even sure you need the "?:" non-capture part. Django would just pass the groups as args which you're likely ignoring anyway.

^^ This is byte-for-byte what I ended up doing, but it turns out Pumpkin Pirate's does work too. Nice! It does need the ?: though.

Thanks guys! :cheers:

Data Graham
Dec 28, 2009

📈📊🍪😋



Has anybody worked with https://pypi.python.org/pypi/django-pdfkit ?

Specifically, I'm having trouble with the rendered page apparently having a race condition where it may or may not be able to pull in all the dependency / include files at render time, like CSS and image files. If it doesn't pull them in in time, the page will render wrong or throw an error, depending. But sometimes it's perfectly fine.

I've found that the only way to avoid this is to include all the CSS inline, instead of as a separately linked file, even though the latter is supposed to work fine.

Anyone have any experience with this?


E: actually I think never mind, this seems to be a problem with wkhtmltopdf, not with Django; I tried another wrapper and it has the same behavior. Fooey.


E2: lol i'm just gonna do this

code:
class MyPDFView(PDFView):

    def get(self, *args, **kwargs):
        try:
            return super(MyPDFView, self).get(*args, **kwargs)
        except:
            logger.warning('PDF generation failed; retrying')
            return self.get(*args, **kwargs)
lmfao owned

Data Graham fucked around with this message at 21:17 on Oct 2, 2017

Data Graham
Dec 28, 2009

📈📊🍪😋



You're talking about the front-end/back-end split. Django doesn't really do anything front-end-wise; it's a back-end platform.

What it sounds like you want is to have your JS talk to a set of API endpoints and fetch/post data to act on in the front-end context. How you build that front-end is entirely outside Django's sphere (theoretically you should be able to swap in a whole different back-end with only minimal changes to your JS). But to build those API endpoints the usual way is http://www.django-rest-framework.org

You can manually build Views that serve up JSON data using vanilla Django if you prefer, but DRF gives you a full-featured and widely understood framework for exposing your models to the front-end via API calls, and it saves you most of the grunt-work of adding CRUD handling to all your views individually.

Data Graham
Dec 28, 2009

📈📊🍪😋



^^ What are the best-practice workflows in those cases where you otherwise would have to generate JS or CSS from back-end variables, like populating a JS var or an image URL?

... You know, for the benefit of the class. :kiddo:

Data Graham fucked around with this message at 23:05 on Oct 26, 2017

Data Graham
Dec 28, 2009

📈📊🍪😋



Like say I want to set the background-image of a class to an image url generated via {% static %}.

I guess I could always make an api endpoint that serves up all the variable URLs I’ll need and updates the classes’ CSS programmatically, but that sure seems like a lot of round trips and subterfuge just to avoid inlining some snippets of css in my base.html. (Plus I wouldn’t be able to benefit from {% static %} directly, which is kinda the whole point.)

Data Graham
Dec 28, 2009

📈📊🍪😋



Hmm, good point. I guess I found myself wanting to keep path independence between my css and images dirs in case I wanted to move things around, but then I’d be updating all the prefixes anyway. It’s not like you can have multiple static roots. Thanks

Data Graham
Dec 28, 2009

📈📊🍪😋



I'm having a dumbass evening and I can't stay up any later beating my head against this one, so I'll throw it out to you guys in case anyone's seen this before.

I'm trying to upload a file (field name "picture") via AJAX to an UpdateView. The picture is on a model called Claim, which has a ForeignKey member called Offer.

code:
class UploadClaimView(UpdateView):
    model = models.Claim
    form_class = forms.ClaimForm
    template_name = 'includes/claim.html'

    def get_object(self):
        claim = get_object_or_404(models.Claim, pk=self.kwargs['claim_id'])
        logger.info(claim.id)
        logger.info(claim.offer.id)
        logger.info(claim.comment)
        return claim

    def form_valid(self, form):
        logger.info(self.object.id)
        logger.info(self.object.comment)
        logger.info(self.object.offer)
        logger.info(self.request.POST)
        logger.info(self.request.FILES)
        self.object.picture = self.request.FILES['picture']
        ... other stuff beyond here


class ClaimForm(forms.ModelForm):
    
    class Meta:
        model = models.Claim
        fields = ['picture']
As you can see, I'm basically just logging my brains out here because I don't get what's going on. My get_object method finds the Claim object just fine, and when I log the values of offer, comment, and other fields, they're present and accounted for. But then in form_valid, when I log those same fields, they're null. The object itself exists, it has the right id, but the comment and offer fields are gone.

I've tried adding the fields as attributes in the form class (and the fields list too), but that doesn't make a difference.

The end result of all this is that the only field that gets saved properly in my form_valid method is the picture, because I'm setting it manually from self.request.FILES. All the other fields get blanked out.

What the hell? What's going on between get_object and form_valid that clears out all the attributes from my Claim object?

Data Graham
Dec 28, 2009

📈📊🍪😋



Never mind my late-night dumbassery; I was using the wrong form, one which had additional fields listed like comment and offer, so they were being cleaned as null :doh:

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah. Your created_timestamp is an actual model field (column in the database), so the documentation you quote doesn't apply to it; it won't create a ReadOnlyField automatically. You'll want to use the read_only=True flag on a DateTimeField like Thermopyle says, to make sure it gets serialized properly.

Defined @properties (what that doc calls attributes) are like the biggest "aha" thing about Django, to take a tangent. Rather than making direct SQL queries and having all your derived logic take place in the view or the template like in old-school frameworks, Django wants you to move all that logic as far back toward the model as you can, so ideally any logic that depends only on the model itself (i.e. where the output can be generated using only the properties of "self", as opposed to needing extra context like the user or the request) should go into model code. That way you can use the model instance in downstream code, like in a view, without having to think about whether it's a raw database field that you're interacting with or just another object property—ideally they all act like object properties and you can treat all your interactions like python code instead of SQL.

Data Graham
Dec 28, 2009

📈📊🍪😋



Adding a @property method to the Thread model is how I'd do it, but assuming you have your ForeignKeys set up properly I would approach it like:

code:
@property
def latest_post(self):
    return self.post_set.order_by('-created').first()
Then you can access t.latest_post.author and whatever other attributes you want in the template. Also .first() will return None for an empty thread and you can handle it cleanly.

Data Graham
Dec 28, 2009

📈📊🍪😋



Bob Morales posted:

What does the @property decorator do for me here? I notice it works without it.

It treats it as a property instead of a method; in other words in python code you can call it with t.latest_post instead of t.latest_post().

Not relevant in templates because the {{ }} syntax doesn't use parentheses. But in code, if you have a function where you can generate some output using only data inherent to the model (i.e. self), and no other parameters, then you can stick that function into the model as a @property and pretend it's just another attribute.

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah, “magic” convenience behaviors save time for experts but they are absolute hell to reverse engineer.

Plus it seems un-Pythonic.

Data Graham
Dec 28, 2009

📈📊🍪😋



What does your form class look like?

What I typically do is specify the form field with a "queryset=None" attribute, and then in the __init__ method for the form I set the queryset for the field based on extra code, like this:

code:
class TicketForm(forms.ModelForm):
    host = forms.ModelChoiceField(required=False, queryset=None, empty_label='(Select host)')

    def __init__(self, *args, **kwargs):
        super(TicketForm, self).__init__(*args, **kwargs)
        self.fields['host'].queryset = Host.objects.filter(system=self.system)
Something like that? Crispy should use this same form code, right? Shooting from the hip here.

Data Graham
Dec 28, 2009

📈📊🍪😋



I finally got sick of telling clients “look you’ll probably have to flush your cache before the new feature will work, hold down shift and refresh” and decided to buckle down and write some kind of static file caching busting thing. Figured I would store a time stamp of the last modification date of every important js and css file in the settings, maybe pass them to all the templates through a context processor. Pain in the rear end but I knew it would be worth it in the end.

Ten minutes of reading later and I’m using https://docs.djangoproject.com/en/2.0/ref/contrib/staticfiles/#manifeststaticfilesstorage

drat I love batteries included :allears:


E: wtf, preview ate all my quotes and apostrophes

Data Graham
Dec 28, 2009

📈📊🍪😋



No, like a basic common project repo that you keep cloning new projects from, like a template.

That’s how I usually go about it, but of course if you have common development you want to feed into all your extant projects it can get out of hand pretty quick.

Data Graham
Dec 28, 2009

📈📊🍪😋



Does the same thing happen with templated data? What about through the manage.py shell?

Would want to narrow it down to a DRF problem, a webserver problem, or a data layer problem...

Data Graham
Dec 28, 2009

📈📊🍪😋



Can you upload them all into a directory, write a mapping text file listing which ones go where/with which records, and then write a Django management script to move them into the appropriate places in your media dir (if necessary) and update the image field (and width/height) in your model?

It’s roll-your-own but it’s how I’ve been spending my week so

Data Graham
Dec 28, 2009

📈📊🍪😋



Okay seriously, why does the awful app keep eating my quotes and apostrophes? In this thread only?

It’s maddening

E: okay so if I look at those same posts on desktop it's fine. Smart quotes getting displayed as blanks in the awful app only I guess?

Data Graham fucked around with this message at 19:25 on Mar 16, 2018

Data Graham
Dec 28, 2009

📈📊🍪😋



The media/ dir is special; ImageField expects a value which is a filename relative to your MEDIA_ROOT, which is media/. So assuming you’re keeping all the project images in a single directory (which you may or may not want to rethink later on, depending on volume and security and other factors), you should set the value of your src field to just be the bare name of the file, no path. Move the file into the media dir, use PIL.Image to get its width and height (your Image class should have width and height fields too) and set those, and then save.

Phone posting from the hip but that should get it going.

Data Graham
Dec 28, 2009

📈📊🍪😋



Celery is so depressing. Sorry I couldn't help, your use case was just outside the realm of what I've successfully dealt with.

Data Graham
Dec 28, 2009

📈📊🍪😋



E: probably missing something obvious here

Data Graham
Dec 28, 2009

📈📊🍪😋



Super psyched for one of my projects actually, the GIS stuff felt half-baked last time I worked with it (a year or two ago).

Data Graham
Dec 28, 2009

📈📊🍪😋



HOLY JESUS GOD

I didn't know you could undo a migration by doing ./manage.py migrate <app> <previous_migration>

THIS CHANGES EVERYTHING



(e. I don't know what I thought reverse_code was for then!)

Data Graham
Dec 28, 2009

📈📊🍪😋



Do you mean application in the sense of what Django considers a "project" (i.e. a top-level single web application), or a django "app" (i.e. a module within a django project)?

If the former, you want a separate database (/schema) per project, because each project maintains its own auth, migrations, content types, and other global structures.

If the latter, Django keeps all the apps (/modules) within the DB schema automatically, like in the "appname" module you would get tables like "appname_widget" and so on.

Data Graham
Dec 28, 2009

📈📊🍪😋



https://docs.djangoproject.com/en/2.0/ref/contrib/staticfiles/#manifeststaticfilesstorage

It changed my life

Data Graham
Dec 28, 2009

📈📊🍪😋



Try using --natural-primary on your dumpdata. That will prevent it from trying to reuse the same pk IDs, and it'll create its own new ones when you import.

Data Graham
Dec 28, 2009

📈📊🍪😋



When I've had to do a wholesale migration from one database to another via management command, I've had to go model by model, in dependency order, and set the id of each object after saving it, then saving it again.

I also save a temporary "old_id" field on every model so I can import the related models by looking up the old ID of the parent object and linking the new related object to it via the new ID.

Data Graham
Dec 28, 2009

📈📊🍪😋



This is more a rabbitmq/Celery question than a Django question, but I'm hoping someone has experience with the former because of the latter.

I'm trying to add a second vhost to my rabbitmq. I currently have one Django project (running through Apache) with a bunch of Celery workers connecting successfully to my local rabbitmq via vhost1. However, as soon as I go

rabbitmqctl add_vhost vhost2

Then the tasks that my project sends to vhost1 no longer work. The celery logs show no tasks being accepted. But then as soon as I "rabbitmqctl delete_vhost vhost2", tasks work again.

Anyone see anything like this? This is on FreeBSD, rabbitmq 3.7.7.

Data Graham
Dec 28, 2009

📈📊🍪😋



Unless you WANT all your clients to get access to your super cool business logic because it's in client-side JS

Data Graham
Dec 28, 2009

📈📊🍪😋



Another consideration is that who says the backend's conventions should bend only to JavaScript's? Your API should be consumable by mobile apps too, which means you also have to think about clients written in Objective-C, Swift, and Java. Or really a client might be anything, including python. If you want your API to be portable it should be agnostic.

Data Graham
Dec 28, 2009

📈📊🍪😋



I have Celery+RabbitMQ running happily on several FreeBSD and Linux servers. A few days ago I stood up a new one on FreeBSD, and for some unknowable reason the Celery clients keep disconnecting themselves, seemingly due to not being able to send heartbeats.

code:
2018-10-31 09:08:33.166 [error] <0.2210.0> closing AMQP connection <0.2210.0> (127.0.0.1:48360 -> 127.0.0.1:5672):
missed heartbeats from client, timeout: 60s
2018-10-31 09:08:34.176 [error] <0.2223.0> closing AMQP connection <0.2223.0> (127.0.0.1:21796 -> 127.0.0.1:5672):
missed heartbeats from client, timeout: 60s
Poking around issue threads seems to turn up that this is just "one of those things" that isn't due to any one particular causal factor, and nobody has any obvious solution despite several putative fixes to this very issue having been put into Celery over the past few years. I spent two evenings trying without success to disable heartbeats and finding only people mumbling in comment sections that you shouldn't do that and here's how you would if you ever wanted to but it isn't supported and just crashes if you try so :shrug:

Found that if I was in this disconnected state, the first async task I tried to send to Celery would always fail, but then on the second try the workers would wake up again and it would start working, so maybe I needed to build some kind of retry thing at the JS level? Urg

I was halfway through writing my own keepalive task to run through celery-beat when I thought "Hmm, can't you also use redis for the broker?"

Installed redis, was up and running with no issues in literally less than a minute. No bizarre config tools, no mutant erlang libraries, no documentation written in broken english, no heartbeat errors. Why is this not the recommended solution

Data Graham fucked around with this message at 03:24 on Nov 1, 2018

Adbot
ADBOT LOVES YOU

Data Graham
Dec 28, 2009

📈📊🍪😋



I'm having problems with session cookies disappearing after an HttpResponseRedirect.

I'm overriding the built-in password recovery views, which do this when you click on the emailed token link (django.contrib.auth.views.PasswordResetConfirmView):

code:
INTERNAL_RESET_URL_TOKEN = 'set-password'
INTERNAL_RESET_SESSION_TOKEN = '_password_reset_token'

...

        self.validlink = False
        self.user = self.get_user(kwargs['uidb64'])

        if self.user is not None:
            token = kwargs['token']
            if token == INTERNAL_RESET_URL_TOKEN:
                session_token = self.request.session.get(INTERNAL_RESET_SESSION_TOKEN)
                if self.token_generator.check_token(self.user, session_token):
                    # If the token is valid, display the password reset form.
                    self.validlink = True
                    return super().dispatch(*args, **kwargs)
            else:
                if self.token_generator.check_token(self.user, token):
                    # Store the token in the session and redirect to the
                    # password reset form at a URL without the token. That
                    # avoids the possibility of leaking the token in the
                    # HTTP Referer header.
                    self.request.session[INTERNAL_RESET_SESSION_TOKEN] = token
                    redirect_url = self.request.path.replace(token, INTERNAL_RESET_URL_TOKEN)
                    return HttpResponseRedirect(redirect_url)

        # Display the "Password reset unsuccessful" page.
        return self.render_to_response(self.get_context_data())
So what happens is, you come in with a URL like reset/MjU0MDJ/56t-6f0eeb72ba42f34ce946/, where 'uidb64' is 'MjU0MDJ' and 'token' is '56t-6f0eeb72ba42f34ce946'. It looks up the userid via base64 decoding in get_user(), and then does the above logic. 'token' is not 'set-password', so it does the 'else' block, where it sets the token in your session, and then redirects you to the url reset/MjU0MDJ/set-password/. This goes through the same logic again, but this time finds the token in the session and does the 'if' block above, resulting in the password reset form.

However, in my setup, after it sets the token in the session cookie and issues the redirect, the resulting /set-password/ page has NO session cookies. No cookies at all, in fact. So they get the "yo you followed a bogus link" page.

If I copy the same URL into a new browser window, it DOES have the session cookie, and it renders the reset form properly. So it's setting the session value properly. But the cookie is being lost during the 302 redirect somehow.

I've tried fiddling with SESSION_COOKIE_DOMAIN and SESSION_COOKIE_SECURE (this is a production server with a valid SSL cert, and all the URLs are using [url]https://[/url] with the same hostname), to no avail.

I'm not finding anything addressing this in the usual places. Django 2.1.7, Python 3.6.

Anyone dealt with this? I feel like it must be familiar ground for some of us.


E: I should note that this worked perfectly fine in Django 1.11 and earlier. I just recently upgraded to Dj2 and Py3, and this apparently stopped working right then.

Data Graham fucked around with this message at 02:40 on Jun 1, 2019

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