In my Django project I need to access constantly the object of the user`s character(a model), where should I store the value of this object ? since I will be using it in multiple views to display content in the template. Should I store in the session, retrieve from the database every time or some other alternative?
class Character(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,primary_key=True)
gold = models.IntegerField(default=gold)
points = models.IntegerField(default = startPoints)
Not sure what exactly means character, but:
If it is not session-based, but permanent information(and I believe that it is) you need to store it in the database to be able to fetch it when the user log in. How you will store it does not really matter - it can be dedicated table if you need it(in this case would be nice to add user as FK) or it could be a field in User table.
Then, if you have Session middleware and Authentication middleware, you will be able to access user object from the request object, so what you will need to do is:
request.user.character
I hope it is helpful.
UPD: the only way to store the data between requests in DB or caching system(if you have non-DB cache or you don't store session in DB but in something faster instead - like Redis or Memcache). I am adraid that is the only way.
For per-session data you can use cookies in some situation, but I think it isn't the case.
Related
I'm working with Flask-restplus and I am at a point where I would like to associate each User in my user model to a type of profile, where each user can be associated with one or many profile types. I'm wondering how you guys would go about this. So far, here's what I'm thinking/planning to do. NOTE: I'm not very experienced in web development, so there's a chance I don't know the best way to accomplish this.
Step 1: Create a one-to-many (clients need to also be employees, see below) field (profile_types) relating to a static table that just lists all possible profile options. EXAMPLE:
PK PROFILE TYPE
1 provider
2 employee
3 client
.....
The idea here is to track different information and allow for different views/endpoints for users who are tied to certain profile types. Example, employees would provide a valid login authentication and be directed to page A while a client would be directed to page B, etc. We're also planning on collecting different data points within each profile model.
So an instance of a user might look like this, user1.profile == [client, employee'].
NOTE: This is more important for data collection (ie age of employee, start date, etc) than it is for creating directives based on permissions.
Step 2: Upon creating the new user, a signal fires off the creation of a profile based on the profile_types supplied to the user instance. I've used signals with django in the past, is there a signal library for Flask?
Step 3: An empty profile instance(s) now exists for that user. It will be up to a superuser to upload data in bulk or manually fill out profile information.
Is this a sensible way to go about this? My other though is to create a bunch of Boolean fields in the User model is_provider, is_employee, is_client, etc. All fields that are True get assigned a profile instance. What's the best way to go about this?
Thanks everyone!
Seeing that are you try to validate multiple profile types, you may use
if user.profile_type in ['employee', 'client']
Now, if you want to add an super user I think you can use this
if user.profile_type in ['employee', 'client'] and user.profile_type == 'superuser'
Now, you relationship is more like 'many-to-many', because you are saying that an client also needs to be an employee, if you mean that some endpoints needs to be accessible for employees and clients, then you need to use a 'many-to-one' relationship (an Stackoverflow question which explains what is that)
For your instances, there is Flask Marshmallow, which has an amazing compatibility with Flask SQLAlchemy if you are using an database, but Flask Marshmallow can work alone.
I would like to create a custome admin view with fields with data that I fill manually, meaning that there's no database table behind.
In my admin.py I have this so far
class TestAdmin(admin.ModelAdmin):
pass
admin.site.register(Test, TestAdmin)
and in the models.py
class Test(models.Model):
test = models.BooleanField(
default=True
)
But with this I receive an error
django.db.utils.ProgrammingError: relation "..._test" does not exist
Django is looking up the table in the database but in my model I need only fields which data I fill manually
It seems that you don't really get what a Model and ModelAdmin are. A Model class is the representation of a database table, and a ModelAdmin is a component that provides administration features for this table and it's content. IOW, when you write that "there's no database table behind", you're missing the point somehow: you cannot have a ModelAdmin without a Model, and you cannot have a Model without a database table.
To make a long story short: you'll either have to
1/ use a model or
2/ write the whole view(s) and templates by yourself and plug them into the admin.
For the second solution, see this question (and it's answers), or just google for "django admin views without models" (there are a couple 3rd part apps that are supposed to help plugin custom views in the admin).
Now the first solution might - or not, depending on your exact needs - be as good as the second one, depending on who populates your s3bucket and how. Without a model, you'll have to query the bucket for a file listing each and every time someone accesses your custom admin view, which might get quite costly. If all the uploads to the s3 bucket are under your control, you can use a model to keep a local file listing "cache" and you'll only need to hit s3 when effectively downloading a file. This also gives you the opportunity to store metadata about those files - which can be used for searching / filtering - and eventually to link your s3 files to other models if needed. And of course this means you get your admin for free ;)
Actually even if you don't have control on those uploads, you may still want to use a model for the above reasons and have a background task (cron job or equivalent) that updatees your table from the s3 bucket contents (or - if s3 provides web hooks - have an API endpoint called by s3 on uploads that updates your table).
The way that django's ORM works is that all class members of a model class that is an instance of model.Field will map to a column in the database.
It is possible to have model properties that does not map to a database table. You could use a #property instead, for example.
class Test(models.Model):
#property
def test(self):
return get_aws_bucket_value(self.id)
#test.setter
def test(self, value):
set_aws_bucket_value(self.id, value)
You have to implement the aws getter/setter functions yourself.
You can use properties as read-only fields in the django admin class. Be careful about using it in the list view if your getter logic needs to fetch data from a remote server syncronously, since that would be a significant performance bottleneck.
If you want to be able to set values for a setter from the django admin, you would have to write a custom ModelForm for TestAdmin.
It is possible to wrangle Django into doing what you want here. But Django's models and admin are based around the ORM, which means using a relational database as persistant storage. If you don't want that, you can find yourself fighting against and overriding the framework more often than benefiting from Django's "batteries included". This project might be better solved with a less monolithic and less opinionated framework such as Flask instead of Django.
I'm using Eve framework and I'm trying to use User-Restricted resource access as described in:
http://python-eve.org/authentication.html#user-restricted-resource-access
I'm doing something like:
class CustomAuth(TokenAuth):
def check_auth(self, token, allowed_roles, resource, method):
# Get user as an instance of UserResource.
if user and hasattr(user, 'id'):
self.set_request_auth_value(user['id'])
request.authenticated_user = user
...
So, there are a few question from my side:
Is it enough for using User-Restricted Resource Access?
How this field adds into user created objects?
Is this additional field called id in my user created objects? Is it possible to rename it?
As I understand it should be named same as it's called in User resource. Is it true?
Does this field (property) applies for newly created objects only? Is it possible to fetch previously created objects by current user following this way?
Well, I want to know an answers for my questions + clarify how it may be used.
Is it an expected way to extract it somehow in my hooks?
user_id = current_app.auth.get_request_auth_value()
current_app.data.driver.session.query(resource).find({'id': user_id})
Is this block of code from hook expected?
How it behaves if my requested resource has its own id field?
P.S. I was reading a post:
https://stackoverflow.com/a/35654252/7335432
The user-restricted access feature prevents users from accessing records they didn't create. The set_request_auth_value() method does:
1) Upon making a POST request to create a record, it automatically adds a field specified as AUTH_FIELD (or auth_field if you only want to do it to a specific resource). So for example, if you declare in settings.py
AUTH_FIELD = "my_auth_field"
and then add
set_request_auth_value(user['id'])
to your authentication method, that means that your app creates a field "my_auth_field" that has its value set to whatever user["id"] is. So if you were to go into Mongo Compass or some other DBMS and manually inspect your records, you'd see a "my_auth_field" field in there.
2) On GET requests when you access those records, Eve checks the "my_auth_field" value against whatever user["id"] is, and only displays the records where "my_auth_field" is equal to user["id"]. Since this field is added automatically when you create a record using Eve, it effectively filters out everything that specific user didn't create.
So yes, it only applies to newly created objects. I'm not sure exactly what you mean by "is it enough", but it doesn't look like 'user' is declared anywhere in your authentication class. You might wanna check out this tutorial they do incorporating user restricted access into token authentication.
I am designing a new AppEngine/Python HRD application. In this application, I need to ensure that each user that registers cannot use a name that has already been assigned to another user, and that if two users attempt to register with the same username at the exact same moment, that only one of them will be given the username.
If I were to put all usernames in a single entity group and use transactions to ensure uniqueness, then the writing of the username/object in a transaction could potentially slow down all registration processes. So this approach doesn't seem like a good idea.
Another option would be to use the username as the key, which has the disadvantage of possibly making it difficult for the user to later change their username.
What is the best/standard approach to achieve this in AppEngine?
Ok.
You don't need to stick all the usernames in a big entity group to guarantee consistency.
Make the username the Key of the datastore entity governing the login.
Then inside a transaction.
Try a get using the username as a key (this is a consistent operation)
if you find it then obviously it's not available
If not found then create the new login entity.
As an aside if you used email addresses then it would more than likely mean no clashes ever. and I am not sure why visible nick names need to be unique, but then you probably have a good reason.
Each actual user object can have a system generated unique id, (this is a separate entity to the login entity).
If you are really paranoid, then look at using memcache CAS operations to effectively act as a lock on the username key and prevent simultaneous operations, though I don't think it would be necessary.
Entities might look like
class Login(ndb.Model):
# other stuff neede for authentication etc..
user = ndb.KeyProperty(User)
#ndb.transactional(xg=True)
#classmethod
def create_login(cls,username):
# maybe pass in extra user details
key = ndb.Key(cls, keyname)
login = key.get()
if login:
raise DuplicateUsernameError(username)
login = Login(key_name=username)
user = User.create_user(login=login.key)
login.user = user.key
login.put()
return (login,user)
class User(ndb.Model):
login = ndb.KeyProperty(Login) # this property is only for convenience.
nickname = ndb.StringProperty()
# etc
#classmethod
def create_user(cls,login_key):
# yes you would pass in more user stuff.
user = cls(login=login_key)
user.put()
# the unique user key is system generated.
return user
This means only a single get() is required to fetch a login, and second to get the rest of the user details but is much cheaper/faster than queries. It also means that the login name/code could be changed over time without disrupting the actual user entity if you really wanted such functionality. Or possibly support multiple login methods for a single user - ie facebook and twitter. It also means a login entity can be removed and login re-used by other people over time, and the user entity can stay if system integrity/history is required.
App Engine allows up to 1 write per second within the same entity group. To surpass that barrier you have to have 60 x 60 x 24 = 86.4k registrations on the same day, which I think you can live with.
If you still think you need any faster process you could use sharding (more typically known for counters - https://developers.google.com/appengine/articles/sharding_counters), which is basically having different tables for users (or usernames) so that you can read them all to check for uniqueness (App Engine is good at doing many reads per second) and have as much better write pace as tables for usernames you add.
More of sharding on writes here - https://developers.google.com/appengine/articles/scaling/contention
Hope it helps.
I'm writing an app for tagging photos. One of the views handles adding new tags and without boilerplate for POST/GET and handling field errors it does this:
tagName = request.cleaned_attributes['tagName']
t = Tag.objects.create(name = tagName)
t.save()
Now in a view for another request to retrieve all tags I have:
tags = Tag.objects.all()
I see the data only after restarting Django development server, which is odd to me. Seems like Tag.objects.all() has some caching mechanism that is not invalidated properly? The data is for sure saved to the database.
The database backend is sqlite. I guess I am either missing some configuration or just forgot to do something simple. Ideas?
Tag.objects.all() is a QuerySet. These do not hit the database until you do something to evaluate them. So, how exactly are you using it in your view? If you are using a generic view and passing the queryset through extra_context, for example, it wouldn't be re-evaluated.
Also, as an aside, Tag.objects.create(name = tagName) will automatically save to the db.