If a user has multiple projects under their account, how do I authenticate the user so that the content is not only specific to their account, but to their default project. Ideally, the project is right at the top portion of the page, inside the base template of the site, right beside the sign-out link. The user should be able to just change the project without signing out and signing back in. The request object should be loaded with the project, so I could query the contacts model like this:
Contact.objects.filter(project = request.project)
Currently, I have to do the same query like this:
user_project = Project.objects.get(user = request.user, project_name = 'summer')
Contact.objects.filter(project = user_project)
A little nudge in the right direction is much appreciated
As far as you'r going to filter the query by request, so I suppose it's gonna be used in a view class. I had the same situation and I fixed it using Mixin view with Class Based View (CBV) and inherit it to all other my Views Class. And inside this Mixin abstract view class, you can add whatever you need and join it to the request.session dictionary-like object
Related
I'm writing a multiuser app, the problem is if I Edit a Product I have the URL:
re_path(r'backend/produkter/edit/(?P<artikel_id>[0-9]+)/$', backend_views.edit_artikel_view),
Which results:
http://127.0.0.1:8000/backend/produkter/edit/36/
Now another User can use this URL because he is authenticated, and it looks not clean to me. Is it possible to go from view / url:
http://127.0.0.1:8000/backend/produkter/
to
http://127.0.0.1:8000/backend/produkter/edit/
and give the ID on another way to the editView?
I think one way to do in your requested format is to use Django Session.
Flow will be like this:
When you click Edit Product, make a post request to the same view with parameter as 'edit_product_id' and value as selected product's id
Set session variable for edit_product_id in the same view function like this:
edit_product_id = request.POST.get('edit_product_id')
request.session['edit_product_id'] = edit_product_id
after this redirect to the editView
On product editView, retrieve the edit_product_id and use it to update the databse.
edit_product_id = request.session.get('edit_product_id')
If this product can not be modified by another user, then for sure this will be related with the logged-in User somehow.
1.) In that case, you don't need pk. Instead you can get the user info in the View itself from request.user, and now you can fetch the product you want to edit for this user. In this case your url will be
http://127.0.0.1:8000/backend/produkter/edit
2.) Second way can be to check the user logged in and compare it with the product user, this can be done with request.user. Something like this :
if request.user.id == product.user.id:
considering you have the this relationship between user and product.
I'm trying to manage my REST API like that :
http://xxx/users/userid[0-9]+/projects/projectid[0-9]+/tasks/taskid[0-9]+/
So I can access the JSON easily in my website. But, the thing is, I defined my view classes using the REST framework generic views. For example, here is my UserDetail view :
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
But of course I don't want all my users to be displayed, I just want my user with the ID userid to be displayed. I don't really know how to do it, I tried
queryset = User.objects.filter(id=userid)
but of course userid is not defined... Any help please ?
Edit : just to clarify, here is the url that leads to this view :
url(r'^users/(?P<pku>[0-9]+)/$', views.UserDetail.as_view(
), name='user-detail'),
First of all, If you want to use class based views, you should read some more about them. They are thoroughly explained on Django's docs and you can read about the specific generics of the framework you're using on the REST framework docs too. I'm not saying that you haven't read those, just that you seem to be missing some basic concepts that are explained there.
Now, to the problem at hand, if you look at the doc's of the generic view you're extending, you can see that it represents the endpoints for a single instance, meaning that it won't act on all your model's instances (as you seem to assume).
Also, you can see that this view is built on top of a series of other classes, the more critical one being GenericAPIView. On there you can see two things:
The queryset class field in this context is meant for filtering the posible instances you can manipulate, not obtaining the specific instance described on your url.
The lookup_field is the field that defines which attribute from your model will be used for getting the actual instance. You should define this field to whatever field you're going to use on your url to identify your object (generally it's pk). It's also important to note that the url should include a keyword argument corresponding to this value.
Internally, the view will take care of calling the get_object method, which usese the lookup_field value to find the specific model, and then feed that object to the serializer and return the result back to the client.
DISCLAIMER: I've never used Django REST framework, I put this answer togheter by reading the relevants docs and based on my experience.
I guess you need this:
Resolve function (django 1.4)
Then in your view class method you can do:
temp1, args, kwargs = resolve(self.request.path)
In general how do we know if user is visiting the page for the first time? Technically, do we store the number of visits to each page in the Model(I am using django) or is there some other pattern that I could follow to ease up the operation.
I m just looking for a design for implementing this.
I think you will have to create your own mechanism for this.
I would make a model storing first visits for every url and user called e.g FirstVisit. Then if a user requests a page in a view you can search if there is an entry in FirstVisit for current user and url and find out if it's his first time or not. After that, if he hasn't visited yet, you store the entry to the FirstVisit model, because he is just going to get the content of the page.
I will try and write the code:
#models.py
class FirstVisit(models.Model):
url = models.URLField()
user = models.ForeignKey('auth.User')
#views.py
def my_view(request):
if not FisrtVisit.objects.filter(user=request.user.id, url=request.path).exists():
#he visits for the first time
#your code...
FisrtVisit(user=request.user, url=request.path).save()
You can create a decorator and put in there this functionality. Then add the decorator to any view you want to store this information and from the decorator pass a flag argument to the view determining if user is there for the first time.
Following #davekr suggestion, I would create a model like FirstVisit with some attributes like ip-address, time registered and instante it on the get method (that is tied to the root url) with some validation if the user is valid or authenticated.
PS: Check this (https://docs.djangoproject.com/en/2.0/ref/request-response/) django docs to indentify the request attributes that could be of your interest to construct the FirstVisit.
Sorry, I am still new to Django, hopefully the question isn't out of place.
When I have the following in my template:
<td>{{ item.last_name }}</td>
By clicking on last name the user will be redirected to the following link in order to edit it.
http://127.0.0.1:8000/contact/edit/?id=1
But then what prevents any logged in user to just inject a different id in there on the browser and edit a record that doesn't belong to him?
Update
I just had an idea when I read the comment and answer below. Rather than using a third party app, couldn't I just create a UserProfile for each user and attach a unique company wide uuid.uuid1(). Each time a loggedin user attempts to edit something, his unique company uuid will be also passed in the link as an additional parameter.
On the edit side, it would harvest this guid and compare it against the logged in user and see if they match. If they do match, he is authorized to proceed with the editing, otherwise he will be redirected.
What do you think? Any weaknesses?
If you use Django's new class based views, e.g. the generic UpdateView, you can extend the dispatch handler.
def dispatch(self, request, *args, **kwargs):
handler = super(MyEditView, self).dispatch(request, *args, **kwargs)
# Only allow editing if current user is owner
if self.object.author != request.user:
return HttpResponseForbidden(u"Can't touch this.")
return handler
In this case, the code verifies that the author field of the model object corresponds to the currently logged in user, before even handling the rest of the request.
You can see a reallife example of this in a project of mine.
When you're using Django auth, always rely on the session mechanism to identify an user instead of making some other id such as uuid1() (except, for example, when you need extra sessions in an e-commerce site under HTTPS).
For the permission part, you could check the ownership directly, mainly as described by Koliber Services. The relationships between Company, User and Contact are crucial for the logic of permission checking. There are many ways to model the relationships and thus the code would differ much. For example:
# a modeling way
User.company -> Company : an user belongs to a company
Contact.contributor -> User : a contact is contributed by an user, would be invalid is user is leaving the company
# could check accessibility by
can_view = contact.contributor.company_id == current_user.company_id
# another modeling way
User.company -> Company : an user belongs to a company
Contact.company -> Company : a contact info is owned by a company, does not share globally
# could check accessibility by
can_view = contact.company_id == current_user.company_id
When can_view is False, user should get a 403 for his unauthorized attempting and get logged.
Normally the above method is enough for content protection(not yet in Django Admin). However, when you have many different types of permission checking and even row-permission checkings, it's better to use some uniform permission API.
Take Django-guardian for example, you could simply map companies to groups and assign can_view permission for a contact for the group representing the user's company. Or, assign the can_view permission to all users in a company when a contact is created by using signal or celery task.
Furthermore, you could use /contact/1/edit/ instead of /contact/edit/?id=1. In this way the int(request.GET('id')) part is moved to urlconf like r'^contact/(?P<pk>\d+)/$', less code and much clearer.
There are some third-party apps that does what you want, its called "row-level permission" where you can give different users different access to specific objects, "Row level" comes from SQL where each object is a row in the database
I use django-guardian to do the job
In the function handling the saving of the data, check to see if the object being edited has the same ID as the presently logged in user.
For example, if the object in question is called EmailPrefs and it has a field called user_id:
Load the EmailPrefs object with the ID of the object being edited
If the user_id does not match the current user, stop further processing
Modify the EmailPrefs object
Save the EmailPrefs object to the database
I have an AppEngine app that I'm migrating to run in Django, using app-engine-patch to get all the goodness of Django - particularly the Admin interface.
One of my models looks like (partially) this:
class Request(db.Model):
requestor = db.UserProperty(auto_current_user_add=True)
When I display a form based on this model I don't display the requestor field, and so when I call the Model's put() method the entity I'm saving doesn't have the requestor property set. This triggers the auto_current_user_add magic, and the user who created the request is automatically added.
Under Django, I'm using the provided Users table. I want this to display as a list of the users of my app, so the model becomes:
from ragendja.auth.google_models import User
class Request(db.Model):
requestor = db.ReferenceProperty(User)
However, this breaks the auto_current_user_add magic in the admin interface - if the user of the admin interface doesn't enter a value for the requestor property, Django sets the property to None, when I'd really like for the Request to have their username inserted automatically.
How can I restore the magic?
My solutions relies on three things:
First: it's possible to override the model's put() method.
Second: users.get_current_user() still provides the correct user, and
Third: ragendja.auth.google_models.User.get_djangouser_for_user() takes a google.appengine.api.users.user object and returns the corresponding Django User object - creating it first if it didn't already exist.
Putting this all together, I have:
class Request(db.Model):
requestor = db.ReferenceProperty(User)
def put(self):
if not self.requestor:
self.requestor = User.get_djangouser_for_user(users.get_current_user())
super(Request, self).put()
This works nicely with the admin interface: the admin can assign any existing user (or use the supplied + sign to create a new user) - if they leave it blank, they'll be assigned as the requestor.
Later when I add a view for users to manage their own requests, this value will be on the 'excluded' list, and the same method will add in their username every time they create a new request.
I'm not sure if this is an optimal solution though; I'm new to Django, so maybe there's a better way to achieve this.