I'm building an app to manage flats:
There are different administrations. Each administration has users. Every administrations owns properties and every property has 1 to n flats.
Sofar so good. That's more or less setup.
No comes the tricky part. The users of administration A should only be allowed to see properties and flats that their administration owns.
How would I best do this?
Assuming that there is a ForeingKey relationship between the Administrator model and the User model, you can right a filter on what the user can see. For example:
class UserCreatesAndViewsSomething(LoginRequiredMixin, CreateView):
model = UserLog (or something like that)
template_name = 'some template you have'
fields = ('field you want to display',)
# This function will submit the form to the database
def form_valid(self, form):
# this will help you determine what the current administrator is
administrator = AdministratorModel.objects.get(user=self.request.user, administrator=self.kwargs['administrator'])
form.instance.user = self.request.user
# This will autopopulate administrator input to the current user administrator
form.instance.administrator = administrator
return super(UserCreatesAndViewsSomething, self).form_valid(form)
# get_context_data will help you determine what the user can see.
def get_context_data(self, **kwargs):
administrator = AdministratorModel.objects.get(user=self.request.user, administrator=self.kwargs['administrator'])
context = super(UserCreatesAndViewsSomething, self).get_context_data(**kwargs)
context['something'] = to_journal_entry.objects.filter(user=self.request.user, administrator=administrator)
return context
I know that's a lot, but if you are at all familiar with Django you can certainly do it. You will have to go through some trial and error, but this is the approach I used for my project.
Finale note, this assumes all your users and user inputs are in the same database and the code helps you get only the relevant information. If you are dealing with high importance clients or or some sensitive information you should probably look into multi tenancy, which will set up a different schema or a different database for each of your clients. This will lead a different code structure.
Hope this helps.
Related
Is there a possibility to check that an instance detail is being opened in django admin?
An example with orders illustrates it well - imagine that there is a new order instance in a list display of order instances in django admin. (data come from outside django)
The order model has the following field which is blank when the instance appears in the list;
ProcessingPersonAdminId = models.IntegerField(verbose_name=_('Processing Person Admin Id'), db_column='ProcessingPersonAdminId', blank=True, null=True)
What I need to do - first person (imagine from sales dep.) that clicks on this particular order instance to view its detail is assigned to it. Before it even displays so the field is already filled in with corresponding user data.
I was thinking about signals but nothing is being saved or updated neither in admin nor in models or anywhere else.
I would appreciate any hint on how to approach this task. Thank you in advance.
Solution 1
Do you mean when the changeview page has been opened in the admin app? If so you can do this:
class OrderModelAdmin(admin.ModelAdmin)
def changeform_view(self, request, *args, **kwargs):
user = request.user()
# do something with user
return super().changeform_view(request, *args, **kwargs)
However, is this really what you want to do? Imagine someone accidentally clicks a wrong page. They are automatically assigned. Or maybe someone wants to look at an order without being assigned to it. Quite apart from anything else, this would also go against the principle that a GET request shouldn't change data.
Solution 2
One alternative would be to override the save_model method in your ModelAdmin:
class OrderModelAdmin(admin.ModelAdmin)
def save_model(self, request, obj, form, change):
user = request.user()
obj.id_of_person = user.id
return super().changeform_view(self, request, obj, form, change)
This way, whenever someone uses the admin to make a change to an order, that person is then assigned that order.
Other things to consider
The admin app is not designed to be a production ready, customer facing app. The only people using it should really be devs, who understand the data they are changing. The sales department definitely shouldn't be using the admin app. For this you should write your own views.
I want to use django groups provided in user groups. The django group permissions set in admin panel. Suppose I created two groups teachers and students. I want to set permissions at generic view level. Some views can only be can view or can edit by either student or teacher. These permission were set in django admin as following:
Now I created a createview as following:
class CreateQuestionView(LoginRequiredMixin,generic.CreateView):
model = Question
success_url= reverse_lazy('questions:list')
fields = ['title','description' ]
def form_valid(self,form):
form.instance.user = self.request.user
#self.object.save()
return super().form_valid(form)
Now I want this view to be accessible by only teacher groups. I cant find a proper way to implement group permission.Something like #group_required may work in this case link but cant find any related documentation. What is correct way to implement this?
You want the PermissionRequiredMixin:
class CreateQuestionView(LoginRequiredMixin, PermissionRequiredMixin, generic.CreateView):
permission = "yourapp.perm_code_name"
model = Question
success_url= reverse_lazy('questions:list')
fields = ['title','description' ]
def form_valid(self,form):
form.instance.user = self.request.user
#self.object.save()
return super().form_valid(form)
Note that you do NOT want to test whether your user belongs to a given group (assuming this group has specific perms) - this is an antipattern. All you care about is whether your user has the required perm, however he has it.
I'm a newbie with django and working on a project where I need to display registered user's last visited pages on their profile page. I have achieved that within my extended user class by adding a new many2many field to my main object which I want to keep history for. In my view, whenever a member makes a request I add the object to member's history. But this doesn't give me the result that I want. Items are not ordered and if user is not logged in it gives User DoesNotExist error. I know there is a better way then this but I could't find it. Probably I'm not on the correct way. I appreciate any help or ideas.
class myObjectView(View):
model = myObject
template_name = 'app/myobject_detail.html'
def get(self, request, **kwargs):
cat = Category.objects.all()
sec = Section.objects.all()
self.item = myObject.objects.get(slug = self.kwargs[u'slug'])
user = User.objects.get(username=request.user.username)
if user.is_authenticated():
if self.item in user.member.history.all():
user.member.history.remove(self.item)
user.member.history.add(self.item)
user.save()
else:
user.member.history.add(self.item)
user.save()
Your approach has drawbacks but is not a bad one if you need long term persistance.
You could easily add an ordering field in your m2m through table (look at docs) to add some sense of ordering. You could also order your m2m through table by its PK, as large PK values would mean newer entries given your current code of removing items and adding them again.
ordered_item_history = (user.member.history.through.objects
.filter(user=user, myObject=self.item)
.order_by('pk').values_list('myObject', flat=True))
That said the easiest way to do something like this is in the session.
request.session.setdefault('history', []).append(myObj)
request.session.modified = True
Now in any view, you can access this ever-growing list of object history via request.session['history']. Modify as necessary to eliminate duplicates.
I haven't found any documentation or tutorials on this topic, haven't received any answers on the IRC channel either so it makes me think I'm looking for the wrong thing. Anyway, resorting to SO after several hours of searching. I'll try to describe what I'm after by example:
I want to create a web application where user could create an account (this part is rather clear
After logging in, user would be able to store his favorite meals
When a user is logged in, he would see a list of his favorite meals and he could edit them
I understand how user can create account and log in. But everything after that is kind of blurry.
After user logs in, let's say he would be presented with a form he could fill in and save. How should the database (models) be designed to handle this? Would each user get his own table? How to retrieve the user stored data (i.e. favorite foods) from the database?
These are the things I'm trying to figure out while learning django/programming in general. As I said I haven't found it described in any books, docs or tutorials I went through.
I would appreciate if you could point me to the right direction. I feel like I'm missing something here.
Basic stuff:
make a foreign key for the user in your model
suppress the user field from the form
save the form with commit=False, set the user to the authenticated user and save the model.
The rest you can get pretty straight forward from the tutorial.
For example:
# At models.py
from django.contrib.auth.models import User
class FavoriteMeal(models.Model):
user = models.ForeignKey(User)
# other fields...
# At forms.py
class FavoriteMealForm(forms.ModelForm):
class Meta:
model = FavoriteMeal
exclude = ('user', )
# At views.py
#login_required
def favorite_meals_view(request):
favorite_meals = FavoriteMeal.objects.filter(user=request.user)
...
if request.method == 'POST':
form = FavoriteMealForm(request.POST)
if form.is_valid():
favorite_meal = form.save(commit=False)
favorite_meal.user = request.user
favorite_meal.save()
...
What you are looking is for is really very basic part of django. I would suggest you to go through tutorial. This would give you a fair amount of idea of how the model relationship could be used to store the data.
https://docs.djangoproject.com/en/1.4/intro/tutorial01/
Some background,
I've been designing a user profile for our Django database system and am currently trying to create a views page to allow the user to edit their account settings (outside of the admin page). I have searched numerous sources, most of which recommend using .get_profile(), but this has not worked in my program no matter what approach I try (to my knowledge and research done). So far I have used the django main pages for .get_profile() to see how to properly use .get_profile() and found the AUTH_PROFILE_MODULE setting ( I will specify my settings in a bit).
Using this site:
http://www.turnkeylinux.org/blog/django-profile I found out some other methods of using .get_profile() but still nothing has worked. (I won't add the rest of the links i've tried as I could go on for a while)
Back to the question, can anyone recommend a method that would work so that I can obtain the users information to set up some default values to maintain their current settings if they choose not to edit them and only update the ones with new submitted values.
So far I have: (hopefully all the relevant parts)
file directory:
~/Documents/project1
settings.py
AUTH_PROFILE_MODULE = "accounts.Account"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
File location:
project1/accounts
models.py
# additional model to incorporate our custom fields to the auth user model
class Account(models.Model):
userLink = models.OneToOneField(User) #link (pointer) to the users other information in User model
birthdate = models.DateField(blank = True) # True makes this field optional
gender = models.CharField(max_length = 1, choices = GENDER_CHOICE, null = True)
def __unicode__(self): # define a unicode for the user to access
return u'%s %s' % (self.userLink.first_name, self.userLink.last_name) # return first and last name
# custom Form to change user account information (can't be a modelForm)
class EditAccountForm(forms.Form):
gender = forms.CharField(max_length = 1)#, choices = GENDER_CHOICE, null = True)
birthdate = forms.DateField(widget = SelectDateWidget()) # True makes this field optional
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
views.py
# Account settings view
#login_required
def AccountSettings(request):
sluggedSettingError = request.GET.get('error', '') # error message with slugged character
settingError = sluggedSettingError.replace('-', ' ')
settingForm = AdditionalForm(request.POST or None) # variable is called in edit_user.html
# might want to have some way to create a new profile if the account doesn't exist
userSettings = Account.objects.filter(userLink=request.user)
# userSettings = request.user.get_profile() # returns the current settings of the users profile
#### Currently trying to get it to let me use get_profile() ########
print "userLink = %s" % userSettings#.user
# print "Gender = %s" % userSettings.gender # testing print
if request.method == 'POST':
# if settingForm.is_valid():
# settingForm.save();
return HttpResponseRedirect('/')
return render_to_response("user_settings.html", {'settingForm': settingForm, 'settingError': settingError}, context_instance = RequestContext(request))
# gender = request.POST['gender'] # pass in the gender variable from post
# birthdate = request.POST['birthdate'] # pass in the birthdate from post
As the code is currently I gave up on the .get_profile() approach and tried doing a query through the available accounts until a matching userLink was found and then saving that to a variable "userSettings". The approach I was taking was to use this variable as userSettings.gender, userSettings.birthdate etc. to access each of the users settings and have them changed if updated and set to the previous value if not (with a series of if statements or some built in Django function).
I'm not sure if this is the most efficient method, or if I should revert back to the get_profile() method. When I was using get_profile() (as it is typed currently in the commented out line) I got the following error
Cannot resolve keyword 'user' into field. Choices are: birthdate, gender, id, userLink
I also tried this approach with a new database using userLink defined as "user" instead to match what the django.docs website specified but still got an error about the Account not existing. I tried creating a try: and except: approach from
https://bitbucket.org/filmaster/filmaster-test/src/1618b18003ed/film20/userprofile/views.py
to handle this error but this also did not yield any positive results.
I am out of ideas on how to get .get_profile() to work, and can't think of anything to allow me to access the users stored information so that it can be edited in a form by them. I'm not sure I understand how to utilize it properly at this point and feel like I'm just running around in circles at this point. If anyone can help me with this I'd appreciate it. I tried to give as much relevant information as I could, but if you need something else to help me out let me know and I will try to include it as soon as I can.
Thanks in advance!
To get the profile attached to a user object, you just need to call get_profile() on the user object:
user.get_profile()
For example,
request.user.get_profile()
The docs on it are in Django Docs. Its worth noting that
The method get_profile() does not create a profile if one does not exist.
So you have to have a trigger to create profiles on creating users ...
user.get_profile() is now depreciated, instead, assuming you have a OneToOne with the user model, you can just use user.profile