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

📈📊🍪😋



Um. Do you maybe have duplicated content in your various different apps' urls.py's?

That you have users listed last in your project urls.py makes me think it's overriding a previous one and it's just the last one loaded. Does it behave differently if you change the sort order of your paths in the project urls.py?

What's in your users/urls.py?

Adbot
ADBOT LOVES YOU

Tuxedo Gin
May 21, 2003

Classy.

Data Graham posted:

Um. Do you maybe have duplicated content in your various different apps' urls.py's?

That you have users listed last in your project urls.py makes me think it's overriding a previous one and it's just the last one loaded. Does it behave differently if you change the sort order of your paths in the project urls.py?

What's in your users/urls.py?

code:
from django.urls import path, include
from django.contrib.auth import views as auth_views
from . import views

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
    path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
    path(r'login-redirect/', views.login_redirect, name='login-redirect'),
    path('profile/', views.profile, name='profile'),
]
And yeah, that fixed it. I moved users above the others and now it is behaving properly. There must be something I've done with users that is overriding other things. Thank you so much for patiently helping out my beginner's problem.

Data Graham
Dec 28, 2009

📈📊🍪😋



No worries! This stuff is a joy once it starts clicking.

I'm not sure what's going on with that rogue URL and I'd want to figure it out until I understood it completely, but at least now you can move past this part and start the real building.

Tip: put in "asdsadasd" or whatever in your browser and you'll get a 404 page with all the paths Django understands (assuming DEBUG = True). Or "users/sdadsasd" for included app urls.

Tuxedo Gin
May 21, 2003

Classy.

I want to be able to pull data from an existing, external postgres database. I put the database in settings.py (I tried both the postgres engine listed in the Django docs and the psycopg2 engine that some folks recommend, and all applical info: host, db name, user, pass). I wrote a model that matches the table I want to work with.

I wrote a simple view (one filter) to test, but I get a ProgrammingError exception, relation "x_x" does not exist.

When I go into the Django shell and do a .all() for the database, the queryset returned is empty, so I'm guessing it just isn't seeing or connecting to my DB. If I manually connect to the database in a .py file within the app, it works, but I can't seem to get the Django integration working. Is there anything I'm missing besides adding to settings.py and creating a model that matches the table?

code:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },
    'archive': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'db_name',
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': 'ip',
        'PORT': '5432',
    }
}

lazerwolf
Dec 22, 2009

Orange and Black
Probably needs a migration did you run makemigrations?

Spime Wrangler
Feb 23, 2003

Because we can.

Also use the manage.py inspectdb command for autogenerating models for existing dbs, probably don’t write your own.

Tuxedo Gin
May 21, 2003

Classy.

Spime Wrangler posted:

Also use the manage.py inspectdb command for autogenerating models for existing dbs, probably don’t write your own.

That's the weird thing. inspectdb doesn't show anything for the database (yet more that leads me to believe it isn't seeing it). That's why I wrote the model manually.

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
Point it at an empty database and run:

manage.py makemigrations
manage.py migrate

and let Django populate the schema of the empty database. Then compare the 2 schemas in Postgres and see what you're missing.

Worse comes to worst, just manually copy over the data from the existing DB into the new empty one.

Tuxedo Gin
May 21, 2003

Classy.

When I add the DB to settings.py, makemigrations doesn't detect any changes/migrations. This is true of both the full database and a new empty one. Is there something that needs to be done other than including the database in settings to have it recognized? Everything I'm reading leads me to believe that that is all it takes and migrations/inspectdb should give you something.

I know the database and credentials/connections are working because I can connect manually in the Django project and do raw SQL queries - just can't get Django itself to make it work.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Tuxedo Gin posted:

(I tried both the postgres engine listed in the Django docs and the psycopg2 engine that some folks recommend, and all applical info: host, db name, user, pass).

Just FYI, they're the same engine. The psycopg2 is there for backwards compatibility reasons, but points to the same thing as the non-psycopg2 engine.

Hed
Mar 31, 2004

Fun Shoe
Do you have multiple schemas installed?

You should be able to manually see what raw SQL the ORM is running for your simple filter. Compare that to you running it yourself with the dbshell.

Tuxedo Gin
May 21, 2003

Classy.

I'm using only one schema (as far as I know - I haven't knowingly changed that).

The results definitely don't look like what I'd expect. I've abstracted the names a bit, but is the "dbname_dbname" in the SQL normal? Probably my code or naming is not right - should the model match the table name? - but that doesn't explain why makemigrations and inspectdb don't return anything for the DB to begin with after I've put it in settings.py

code:
@user_passes_test(permissions)
def username_search(request):
     results = DBModelName.objects.using('dbname').filter(username='tuxedogin')
     render_to_response('app/records.html', {"results" : results})
code:
ignored_wrapper_args	
(False,
 {'connection': <django.db.backends.postgresql.base.DatabaseWrapper object at 0x0000026C69E0BDC8>,
  'cursor': <django.db.backends.utils.CursorDebugWrapper object at 0x0000026C69DD5DC8>})
params	
('tuxedogin',)
self	
<django.db.backends.utils.CursorDebugWrapper object at 0x0000026C69DD5DC8>
sql	
('SELECT "dbname_dbname"."id", "dbname_dbname"."location", '
 '"dbname_dbname"."username", "dbname_dbname"."display_name", '
 '"dbname_dbname"."message", "dbname_dbname"."item", '
 '"dbname_dbname"."user_id", "dbname_dbname"."count", '
 '"dbname_dbname"."amount", "dbname_dbname"."vip", '
 '"dbname_dbname"."notes", "dbname_dbname"."tags" FROM '
 '"dbname_dbname" WHERE "dbname_dbname"."username" = %s  LIMIT '
 '21')
Meanwhile, running the following from a .py file within the project works perfectly so I could just do it all like this but since this entire project is to learn Django I'd like to figure out how to do it properly:
code:
try:
    print(connection.get_dsn_parameters(),"\n")
    cursor.execute("SELECT version();")
    record = cursor.fetchone()
    print("You are connected to - ", record,"\n")
    cursor.execute("SELECT * FROM table WHERE username='tuxedogin' ORDER BY timestamp DESC LIMIT 10;")
    for record in cursor:
        print(record)
except (Exception, psycopg2.Error) as error :
    print ("Error while connecting to PostgreSQL", error)
finally:
        if(connection):
            cursor.close()
            connection.close()
            print("PostgreSQL connection is closed")

Data Graham
Dec 28, 2009

📈📊🍪😋



Let's be clear about how the model names translate to database/table names...

The table names are prepended with the "app" name, where an "app" is a module within your Django project. So in your project you'll have an "app" (which would have been created via manage.py startapp) called, say, "myapp", and myapp/models.py would have:

Python code:
class MyModel(models.Model):
    ...
This will translate to a DB table named "myapp_mymodel"; that's how it would name newly created tables that are created via migrations.

If your existing table is named something else, you need to put this into your MyModel model:

Python code:
    class Meta:
        db_table = 'MyExistingTable'
inspectdb should have figured this out automatically, but that's how that works.

Tuxedo Gin
May 21, 2003

Classy.

Data Graham posted:

Let's be clear about how the model names translate to database/table names...

The table names are prepended with the "app" name, where an "app" is a module within your Django project. So in your project you'll have an "app" (which would have been created via manage.py startapp) called, say, "myapp", and myapp/models.py would have:

Python code:
class MyModel(models.Model):
    ...
This will translate to a DB table named "myapp_mymodel"; that's how it would name newly created tables that are created via migrations.

If your existing table is named something else, you need to put this into your MyModel model:

Python code:
    class Meta:
        db_table = 'MyExistingTable'
inspectdb should have figured this out automatically, but that's how that works.

That was it. Still no idea why inspectdb won't do anything with this db, but now I've got a bunch of objects returned from the DB on my page, so now I can move on and work on handling and displaying the data. Thank you SO much. Everyone in this thread have been extremely helpful. Data Graham, you especially have been very patient and clear in your explanations. Y'all are awesome.

CarForumPoster
Jun 26, 2013

⚡POWER⚡
I'm trying to set up analytics tool Segment on a Django project. Once a user has logged in, I want to attribute them with their previous history.

The Segment Javascript that sits on my website seems to generate a user id, what I can't figure out is how to use the one it has created nor how to send it one so I can use the code shown in the docs (linked above) on login to identify them:
code:
analytics.identify('019mr8mf4r', {
    'email': 'john@example.com',
    'name': 'John Smith',
    'friends': 30
})
EDIT: I'm super dumb and just templated it in to the javascript in my base html file.

CarForumPoster fucked around with this message at 18:52 on May 19, 2020

KICK BAMA KICK
Mar 2, 2009

If I migrate a OneToOneField to a ForeignKey do any values that are already present stay as the only member of the new set?

porksmash
Sep 30, 2008
Yes. I did that once, was pretty seamless. Schema-wise it just drops a unique constraint IIRC.

Data Graham
Dec 28, 2009

📈📊🍪😋



Data Graham posted:

Kind of a long shot but for the Django-in-production veterans out there —

Have you ever noticed weird spates of users running into the CSRF failure error, when there's no obvious reason for it?

The documentation is pretty clear about what kinds of user workflows lead to the CSRF token invalidation (i.e. you load up a login form page in one tab and then another login page in another, and then you use the first tab to login). So it's fairly understandable that a user might run into it a lot if they're in the habit of switching tabs and logging in/out of different accounts all the time. But from my logging I'm seeing a lot of cases where a particular user is hitting the error a LOT of the time, to a degree that doesn't seem warranted by the forensics. I'm logging every time the login form gets loaded and every time the login form is posted, and they're getting CSRF rejection at times when there is not obviously an open login tab or anything like that.

I also have another site where one user tried to do a bunch of QA and ended up getting CSRF errors on all the API calls, right in the middle of a session, though they weren't doing a lot of logging in/out at the time (except part of what they were testing was a lot of logging in/out). But it still seems weird that they would be hitting the error as much as they were — because you should still be able to logout/in all you want and never get the error, unless you're deliberately loving around with multiple tabs/browsers/devices. Which they weren't.

Basically I'm at a loss as to what kind of mutant workflow these people are using, and I can't reproduce it myself. So what I'm asking is, has anyone out there dealt with mysterious CSRF errors that don't seem to be arising from the obvious documented workflows? I'm grasping at straws and the best I can do is set a custom CSRF failure page that says "hey you might be using a stale login from another tab or something, click here to logout and try again idk :shrug:", which sucks.

Just want to follow this up with a bit of where-things-stand-now --

quote:

<ip> - - [24/May/2020:01:12:29 -0400] "POST /client/login/ HTTP/1.1" 302 - "https://mysite.com/client/login/" "/client/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.2 Safari/605.1.15"
<ip> - - [24/May/2020:01:12:31 -0400] "POST /client/login/ HTTP/1.1" 200 1641 "https://mysite.com/client/login/" "/client/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.2 Safari/605.1.15"

This is the poo poo I'm seeing. Someone posts the login form, authentication succeeds server-side, it issues a 302 with the "next" value for the redirect, and ... then a couple seconds later they send the same POST again, which gives them the CSRF error.

Note that there is no GET in between, either for the "next" page or for the login page again. All I can think is that somehow their browser is losing the connection and failing to see the 302 response or respond to it, so they just hit Reload and it re-submits the form.

This may or may not be anything I can have any control over. Anybody have any thoughts though on what the right way to deal with this is, UX-wise? Try to capture these situations and just push the user to the /client/ page (or whatever they were asking for) if it detects that they're successfully authenticated? Put up a big "lol ur stupid" page like I have now? Just ignore it and hope they don't blame me for whatever weird browser situation they've got going on?

It just feels like there's got to be some obvious common factor here that's unique to my situation that nobody else has ever encountered or had to deal with apparently.

Data Graham fucked around with this message at 23:03 on May 24, 2020

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
Are you logging the request & response headers? (If that's too verbose, you could only do it from the IP/UserAgent of the problematic users).

It's a long-shot, but if your site's cookies go over 8kB total then the browser won't send them.

Data Graham
Dec 28, 2009

📈📊🍪😋



Which headers should I be logging? I can add more headers to the Apache logs, but only on a whitelist basis (if I know what they are beforehand).

Just had another occurrence where (over the course of ~1 sec) it went POST (302) -> GET (302) (as expected) -> GET (200) -> POST of the same form as the first again, leading to the CSRF error. So it served up the correct authenticated page, and then the user went and POSTed the login form again for unknown reasons, 1 second after the first POST.

I've seen this happen on both mobile and desktop, and the initial login form has a referer leading from a "login" link on a different page (as intended), so this isn't about a saved bookmark causing problems somehow. And it's not really clear whether there are any users who are more problematic than others; someone will hit the error out of the blue, then they'll log out and retry it and it'll work fine. Then it'll all be okay for days and then it'll randomly happen to someone else who's been using the site fine the whole time. If I didn't know better I'd think this was happening because they are literally doing the one thing that legitimately triggers the CSRF error, i.e. hitting "back" and submitting the form again, like, for fun I guess.

Total cookie size is ~100 bytes.

I've been wrangling Apache for no-poo poo nearly 25 years and it's never behaved this weirdly. Feel like I'm taking crazy pills


e: Just noticed that this time (which was mobile) the second URL in the log, which is the "Location:" header, was blank in the second POST, whereas in the previous one I posted it was "/client/", i.e. the redirect URL if it had been a successful 302. So I don't know wtf to make of that

Data Graham fucked around with this message at 00:21 on May 26, 2020

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
I'd look at Cookie: and Set-Cookie: since those are the ones that are going to be storing your sessionid and CSRF tokens. If either of those change between the first POST and the 2nd then that might explain the behavior, if not the root cause.

Edit: yeah and Location too. A blank Location: is definitely a server-side problem, no idea how a browser would react to that.

Also I think I asked this before, but did you ever determine exactly how the CSRF was failing? Missing, corrupted, expired, etc?

minato fucked around with this message at 01:42 on May 26, 2020

Data Graham
Dec 28, 2009

📈📊🍪😋



When the second POST comes through, it's exactly the same as the first one, with the same CSRF token in the form. Data-wise everything being submitted is the same. It's behaving just as though the user hit Back, entered their password again, and clicked Submit.

So to be clear it's expired, because they already successfully used that token.


minato posted:

Edit: yeah and Location too. A blank Location: is definitely a server-side problem, no idea how a browser would react to that.

WRT this, the second POST results in a 200, not a 302, because it's serving up my custom "hey you got a bad CSRF my dude" page instead of the Django default 403. From my understanding a 200 response shouldn't necessarily have a Location header, since it's basically just used for redirects. What I'm saying is that between the first occasion I posted the other day and today's, in one case it had the Location header set, and in the other it didn't, but both were 200 responses. I don't know if it's meaningful or not because this is occurring on the second POST which is not the problem I'm trying to solve, what I'm trying to figure out is why they're making that second POST to begin with. The first one's successful, they're logged in, idk why they're going back and trying to login again.

Data Graham fucked around with this message at 02:06 on May 26, 2020

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
This sounds like the TCP connection is getting reset. Server receives + processes request, sends response, but the client only receives a TCP RST. Browser shrugs and assumes the POST never got through, so it sends it again, according to HTTP 1.1 8.2.4 Client Behavior if Server Prematurely Closes Connection. This would explain why it's not consistently reproducible, and only occurs to certain groups of users.

The RST could be getting sent by the server, a load balancer, a TLS terminator, NAT gateway, or a corporate web proxy. Wiresharking would prove the theory, but you'd have to be tapping the packets right in the middle; wiresharking on the server wouldn't necessarily show any RSTs getting sent.

Assuming that's the cause, you can try to solve it at the network level or the software level. As you may not have much control over the network level, you might just have to adapt the CSRF checker to allow dupes. You don't want replay attacks, so maybe get the CSRF checker to somehow add the sessionid into the CSRF token. That way an attacker would have to steal both the sessionid and the CSRF token to successfully execute an XSS.

Data Graham
Dec 28, 2009

📈📊🍪😋



Ugh, I was worried it was pointing in this direction. I'm super reluctant to go tearing out the wires in anything security-related, but it seems like this is something that must have come up for other people often enough that there would be explicit handling in the csrf module, or even a setting to toggle it on and off depending on your network's behavior. Googling I'm finding bupkus on this topic.

I don't suppose it can be as simple as overriding the CsrfViewMiddleware to "If the request.user.is_authenticated, return None"? Does that cover the sessionid requirement you're talking about? i.e. can an attacker fake being authenticated? This feels like a dumb question.

Data Graham fucked around with this message at 13:21 on May 26, 2020

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
No, you can't just skip the CSRF check if the user is authenticated. CSRF attacks rely on the user being authenticated. CSRF is just a way of saying "the form this user just POSTed was created by the server, not by some hacker" so whatever you change has to fundamentally support that.

A quick look at Django's CSRF FAQ says this:

quote:

Why might a user encounter a CSRF validation failure after logging in?
For security reasons, CSRF tokens are rotated each time a user logs in. Any page with a form generated before a login will have an old, invalid CSRF token and need to be reloaded. This might happen if a user uses the back button after a login or if they log in a different browser tab.
The default django.contrib.auth code calls rotate_token. If you didn't rotate the token after login then this would solve your problem, but reduce security a little bit. For an intranet app or an app where people must login to access any functionality, this is probably fine.

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
And just a word of warning; removing "rotate_token" on login will "fix" this problem but it won't stop double-POSTing due to wonky TCP connections. So on every other form on your site that results in creation of some resource, you'll need to add code to detect the double-POST.

One technique; if the POST is going to create something with a unique ID, use a UUID and insert it into the form itself, don't just use the DB's next available sequence number. The server's POST processor should pre-check to see if the UUID already exists in the DB, and if so just redirects the user to the resource's page. That way if someone double-POSTs, the 2nd request won't create a 2nd resource.

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah, good call, thanks. Fortunately I already have that UUID behavior for one of the sites that this happens to (it's a social-media sort of deal where it has to support previews of posts that don't exist in the DB yet, so it needs a UUID to attach media to and persist locally). And I've got the override login code working in a side branch for the main problem-child site.

But ... even so, it feels like a bad idea, and I'd much rather it just not get into that situation in the first place. It's a bad smell that there's nobody talking about this behavior or common best-practice mitigations. Since the hosting infrastructure is being handled by my ever-popular and super aggro business partner this'll be a fun one to try to pin on him ..

All your input is much appreciated indeed.

Data Graham
Dec 28, 2009

📈📊🍪😋



Thinking about this some more, and why some of my sites in the same infrastructure never seem to generate any CSRF errors or complaints — it strikes me that my smoothest-running site doesn't use a vanilla-forms style login page at all, but an AJAX style one, where it submits the credentials in an async call, authenticates the session, and then reloads the page. So in a situation like that, if a person gets a TCP reset, it'll still reload the page regardless, meaning it would get a new CSRF token, and if they try again it works fine.

This is only a problem in vanilla-forms login pages, where they have a possibility of going "back" and resubmitting (or the browser helpfully doing it for them).

I'm wondering if it isn't a better UX plan all around to go that AJAX route, since that way it'll be transparent to the user, and at worst they'll just have to enter their credentials again, rather than getting confronted with a weird incomprehensible error and having to logout and do a dumb dance for no reason they can tell.

It means a whole bunch of interesting workflow additions for my sites that use OTP / two_factor, but oh well, that's life I suppose.

In any case I really don't want to have to chase EVERY occurrence of this crap because the one internal user it happens to all the time (because as part of his job he's always logging in and out of various accounts) just today got CSRF'd when he apparently went back and resubmitted a login form he had initially loaded 30 MINUTES PRIOR, so eat me buddy :fuckoff:

KICK BAMA KICK
Mar 2, 2009

A little confused: for one of my models there's an image that would be associated with each row, but this model is for a fixed set of data I already have -- all the rows are already in the table, I'm not creating any as my application runs. So should I use an ImageField on the model to point to that image or are those just static files I should just give predictable names to reference in a template? With upload_to language in all the ImageField and FileField documentation I can't tell if that's just intended for files being submitted by users at runtime.

Data Graham
Dec 28, 2009

📈📊🍪😋



Under the hood an ImageField (or FileField) is just a CharField for storing the path relative to the MEDIA_ROOT. What the ImageField gives you is a bunch of extra convenience methods and properties, like "url" and "path" and (with help of the associated columns) "width" and "height". It's especially helpful when using templates and forms, since it has built-in widgets for that too.

So set up the ImageField with the "upload_to" handler set up to point to the current location where the files are sitting, and then you can write code around your model that leverages those additional methods and properties. There's nothing saying you have to; you can use a CharField and do all the handling yourself (or don't do any if you don't need to), but ImageField saves you the effort.

KICK BAMA KICK
Mar 2, 2009

Data Graham posted:

Under the hood an ImageField (or FileField) is just a CharField for storing the path relative to the MEDIA_ROOT. What the ImageField gives you is a bunch of extra convenience methods and properties, like "url" and "path" and (with help of the associated columns) "width" and "height". It's especially helpful when using templates and forms, since it has built-in widgets for that too.

So set up the ImageField with the "upload_to" handler set up to point to the current location where the files are sitting, and then you can write code around your model that leverages those additional methods and properties. There's nothing saying you have to; you can use a CharField and do all the handling yourself (or don't do any if you don't need to), but ImageField saves you the effort.
Thanks! So you'd use an environment variable to point MEDIA_ROOT at the right place for your development environment vs. production, and django.conf.urls.static.static() is the shortcut to serve them in debug mode.

Data Graham
Dec 28, 2009

📈📊🍪😋



Yeah, though media and static are two separate things (media for variable content, static for site assets). I would class your images as media, since they're attached to data.

You shouldn't have to do anything special with the static urls code-wise to make it work in runserver; if you have STATIC_URL and STATIC_ROOT set correctly then {% static %} calls in templates (and direct calls to /static/) should work fine.

It's media that needs special tinkering to make it work in dev mode/runserver, like:

Python code:
from django.conf.urls.static import static

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

KICK BAMA KICK
Mar 2, 2009

static() even does the DEBUG check for you since that's its intended use case:
Python code:
    elif not settings.DEBUG or urlsplit(prefix).netloc:
        # No-op if not in debug mode or a non-local prefix.
        return []
at least from a certain version

I haven't actually done anything with static files in this project; my frontend is just baby HTML in templates and forms so far. Learning some CSS is still on the to-do list.

KICK BAMA KICK fucked around with this message at 22:00 on May 30, 2020

CarForumPoster
Jun 26, 2013

⚡POWER⚡
I need to make user logins for a Django site where I snail mail the usernames and passwords to people and I can't figure out how to externally check if a user exists or create a new user from a python script.

Whats a decent way to create new usernames and passwords externally from a django site using a python script?

The site hosted on AWS ElasticBeanstalk w/ an RDS database.

EDIT: Should I just write a script to SSH into my instance and then try it via the django shell? Is there a recommended SSH via python library? I see a few different ones all looking pretty dated.

CarForumPoster fucked around with this message at 19:21 on Jun 5, 2020

IAmKale
Jun 7, 2007

やらないか

Fun Shoe

CarForumPoster posted:

I need to make user logins for a Django site where I snail mail the usernames and passwords to people and I can't figure out how to externally check if a user exists or create a new user from a python script.

Whats a decent way to create new usernames and passwords externally from a django site using a python script?

The site hosted on AWS ElasticBeanstalk w/ an RDS database.

EDIT: Should I just write a script to SSH into my instance and then try it via the django shell? Is there a recommended SSH via python library? I see a few different ones all looking pretty dated.
What if you create a new API endpoint to a custom view that you POST a username + password to? It'd attempt to create the user account, or could return a 400 if an account with that username already exists.

If you secure it with token auth (via, say, Django Rest Framework), you can expose the new endpoint to the public while ensuring that only you can interact with it.

Data Graham
Dec 28, 2009

📈📊🍪😋



Really what's wrong with just adding users through the admin?

How automated does it need to be?

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Data Graham posted:

Really what's wrong with just adding users through the admin?

How automated does it need to be?

My sales enrichment team is using an enrichment web app I made to create 5000+ users/year. I want to make a button for them to generate the creds but it complicated the explanation.

IAmKale posted:

What if you create a new API endpoint to a custom view that you POST a username + password to? It'd attempt to create the user account, or could return a 400 if an account with that username already exists.

If you secure it with token auth (via, say, Django Rest Framework), you can expose the new endpoint to the public while ensuring that only you can interact with it.

This sounds exactly like what I want but I've not tried something like this before. Looking to spend max 2-3 days on it.

EDIT: https://medium.com/swlh/build-your-first-rest-api-with-django-rest-framework-e394e39a482c

This looks pretty easy actually, Ill give it a try early next week

CarForumPoster fucked around with this message at 20:46 on Jun 5, 2020

minato
Jun 7, 2004

cutty cain't hang, say 7-up.
Taco Defender
I would create a manage.py command to create the user (there's already a built-in one that creates a superuser, you could base your implementation off that sample code), and the built-in "changepassword" management command to set their new password, and then tie it all together with a local bash script that would SSH into the server:

code:
#!/bin/bash
new_user=blah
new_password=blah
ssh someuser@myserver "/bin/bash" <<EOF
  set -o errexit
  manage.py create_user "${new_user}"
  manage.py changepassword "${new_user}" "${new_password}"
EOF

CarForumPoster
Jun 26, 2013

⚡POWER⚡

IAmKale posted:

What if you create a new API endpoint to a custom view that you POST a username + password to? It'd attempt to create the user account, or could return a 400 if an account with that username already exists.

If you secure it with token auth (via, say, Django Rest Framework), you can expose the new endpoint to the public while ensuring that only you can interact with it.

So using the DRF looks like the winning option and looks pretty easy. I got it up and running pretty fast, got an API token, etc. When I changed from listing all data about all users to trying to return the data for specifically the logged in user I now get the below error:

code:
TypeError at /api/[endpoint]/

'User' object is not iterable

Django/Python Version: 1.11.24/3.7.4
in views.py
code:
class CaseViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAdminUser,)
    # queryset = Case.objects.all()
    serializer_class = CaseSerializer
    def get_queryset(self):
        return Case.objects.filter(self.request.user)
If I try to get just the current users object with that function, I get the error. If I make my queryset var all "Case" objects, works as expected. (i.e. uncommenting the line and commenting out the function. makes it work) There should only be one User per Case

Any help? I don't see how I'm trying to iterate over User there.

CarForumPoster fucked around with this message at 15:30 on Jun 9, 2020

Adbot
ADBOT LOVES YOU

NtotheTC
Dec 31, 2007


CarForumPoster posted:

So using the DRF looks like the winning option and looks pretty easy. I got it up and running pretty fast, got an API token, etc. When I changed from listing all data about all users to trying to return the data for specifically the logged in user I now get the below error:

code:
TypeError at /api/[endpoint]/

'User' object is not iterable

Django/Python Version: 1.11.24/3.7.4
in views.py
code:
class CaseViewSet(viewsets.ModelViewSet):
    permission_classes = (IsAdminUser,)
    # queryset = Case.objects.all()
    serializer_class = CaseSerializer
    def get_queryset(self):
        return Case.objects.filter(self.request.user)
If I try to get just the current users object with that function, I get the error. If I make my queryset var all "Case" objects , works as expected. (i.e. uncommenting the line and commenting out the function. makes it work)

Any help? I don't see how I'm trying to iterate over User there.

objects.filter expects keyword arguments that it tries to iterate over: filter(blah=self.request.user) where blah is the name of the foreign key field for user on your Case model

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