I'm trying to add a search box for users on the webpage to see his profile, and if the user doesn't exist, then I have the option to create it.
In flask, I used a solution that used jquery for the autocomplete, and when no one was found, it would simply put "Create_user" as the text submitted in the form, and then redirect to the url for user creation. I was not able to port this to django(javascript is not my forté and I'm starting django.)
So I tried django-autocomplete-light, but while the autocomplete worked, I found no way to replicate the behavior that would redirect me to the user creation page in the case no one was found. (the create exemple in the docs only allow to create a simple entry, while I need to create a user based on a model)
Any leads on how to accomplish this with django?
That's what i was looking few days ago, i found this
Example Admin code for autocomplete
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django import forms
from selectable.forms import AutoCompleteSelectField, AutoCompleteSelectMultipleWidget
from .models import Fruit, Farm
from .lookups import FruitLookup, OwnerLookup
class FarmAdminForm(forms.ModelForm):
owner = AutoCompleteSelectField(lookup_class=OwnerLookup, allow_new=True)
class Meta(object):
model = Farm
widgets = {
'fruit': AutoCompleteSelectMultipleWidget(lookup_class=FruitLookup),
}
exclude = ('owner', )
def __init__(self, *args, **kwargs):
super(FarmAdminForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk and self.instance.owner:
self.initial['owner'] = self.instance.owner.pk
def save(self, *args, **kwargs):
owner = self.cleaned_data['owner']
if owner and not owner.pk:
owner = User.objects.create_user(username=owner.username, email='')
self.instance.owner = owner
return super(FarmAdminForm, self).save(*args, **kwargs)
class FarmAdmin(admin.ModelAdmin):
form = FarmAdminForm
admin.site.register(Farm, FarmAdmin)
Source code
https://github.com/mlavin/django-selectable
and
Documentation
http://django-selectable.readthedocs.org/en/latest/
Hope this will help you too
Related
I just recently started working on a planner app using Django. I made a new User class that extends Django's User class. This is the code:
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
projects = []
The projects list is for all the projects the User has. Below is the model for Project and the view this is used in:
class Project(models.Model):
title = models.CharField(max_length=60)
def dashboard_view(request, *args, **kwargs):
if request.user.is_authenticated:
context = {
'projects' : request.user.projects
}
return render(request, 'dash.html', context)
else:
return redirect('login')
This works temporarily, but when I end the server, it turns back into an empty list. Is there any equivalent for this in the form of a model field type? Thanks guys!
There is a better method. In your project model, you can add a field like
from django.conf import settings
user = models.ForeignKey(settings.AUTH_USER_MODEL,...)
And in your view, you can use something like
request.user.project_set.all()
this gives you access to all projects for the logged in user.
I'm a total newbie to django so this may well have an obvious answer but so far google hasn't worked out for me.
I have this skeleton application using Django 1.8.
I have a simple model that has an owner field which is a ForeignKey to Group.
When a user is logged in I would like to show only the items that he/she has access to. Access being determined by the fact that the user belongs to the same group.
model.py
class Device(models.Model):
name = models.CharField(max_length=100,db_index=True)
owner = models.ForeignKey(Group)
def __str__(self):
return self.name
views.py
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views import generic
from .models import Device
from django.contrib.auth.models import Group, User
class IndexView(generic.ListView):
"""
This renders the index page listing the devices a user can view
"""
template_name = 'devices/index.html'
context_object_name = 'devices_list'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(IndexView, self).dispatch(*args, **kwargs)
def get_queryset(self):
"""
Return the devices visible to the logged-in user
"""
return devices=Device.objects.all()
What I don't seem to be able to figure out is what to put in the .filter() instead of .all() call in my get_queryset method.
Updated based on Jean-Michel's feedback.
I don't have a Django environment in front of me at the moment, but this might be a good start:
return devices=Device.objects.filter(owner=self.request.user.groups.all())
Alternatively, Django's ORM uses double underscore (__) to access field lookups. These can be used to get values greater than (__gt), or in a list (__in) amongst other lookups (see the docs).
return devices=Device.objects.filter(owner__in=self.request.user.groups.all())
This kind of depends on where the user object is located. I'm assuming the logged in user is kept as a class attribute, i.e., self.user. Per, Jean-Michel's comments, the user object is attached to the request. So we can access it from self.request.user.groups.
Finally, you can access specific fields on models using the double underscore notation as well (__), this example is from the docs:
# Find all Articles for any Reporter whose first name is "John".
>>> Article.objects.filter(reporter__first_name='John')
[<Article: John's second story>, <Article: This is a test>]
Django and programming noob here. I've made an application I'd like to deploy, but I need to figure out how to limit access to the UpdateView to the creator of that object, and I'm stumped.
Currently a user can use the CreateView .../universities/create/ to create a university object, but then any user can use .../universities/update/ to edit that object. I want to configure this so only the user who is the creator (any user with the ManytoMany attribute 'administrator') of that university has access to the UpdateView for their university object.
Any advice would be appreciated. I've spent a few days on this and I haven't made much traction...thanks for reading.
models.py
class University(models.Model):
name = models.CharField(max_length=100)
about = models.TextField()
administrators = models.ManyToManyField(User)
profile_picture = models.FileField(upload_to=get_upload_file_name, blank=True)
def __unicode__(self):
return unicode(self.name)
def get_absolute_url(self):
return reverse('university_detail', kwargs={'pk': str(self.id)})
views.py
class UniversityCreateView(CreateView):
model = University
form_class = UniversityForm
template_name = 'university_create.html'
def form_valid(self, form):
f = form.save(commit=False)
f.save()
return super(UniversityCreateView, self).form_valid(form)
class UniversityUpdateView(UpdateView):
model = University
form_class = UniversityForm
template_name='university_form.html'
You can use UserPassesTestMixin as the documentation says:
limit access based on certain permissions or some other test
just implement test_func(self) that returns True if the user should enter the view.
You might write a code like this:
class UniversityUpdateView(UserPassesTestMixin,UpdateView):
def test_func(self):
return self.request.user.administrators_set.filter(pk=self.get_object().pk).exists()
model = University
form_class = UniversityForm
template_name='university_form.html'
youll have to include permission decorators on your views , further info is here https://docs.djangoproject.com/en/dev/topics/auth/ , & https://docs.djangoproject.com/en/dev/topics/auth/default/#topic-authorization
so if you want to limit your updateview to any user with the ManytoMany attribute 'administrator', youll have to do something like this:
views.py
from appname.users.decorators import requiresGroup
from django.contrib.auth.decorators import login_required
class UniversityUpdateView(UpdateView):
model = University
form_class = UniversityForm
template_name='university_form.html'
#method_decorator(requiresGroup("groupname" , login_url='/accounts/login/'))
def dispatch(self, request, *args, **kwargs):
return super(UniversityUpdateView, self).dispatch(request, *args, **kwargs)
also if you havent already youll have to include the following at the top of your models.py
from django.contrib.auth.modes import user
though Ill assume its there as youve defined your administrators with the user model
then go to the group seetings in the django admin ( should be a url like localhost/admin/auth/group , add your special adminstrator group name, then go to the admin user section (localhost/admin/auth/user), then make sure they have been put into the adminstrator group
then replace "groupname" in the #requiresGroup decorator with the actual name of the user group
the #requiresGroup decorator isnt a standard decorator, so it has to be written
make a folder path and file like appname/users.decorators.py
then in decorators.py write
from functools import update_wrapper , wraps
from django.utils.decorators import available_attrs
from django.http import HttpResponse, HttpResponseRedirect
def requiresGroup(groupname):
def decorator(view_function):
def _wrapped_view(request,*args,**kwargs):
if request.user.groups.filter(name=groupname).count()!=1:
return HttpResponseRedirect("/")
else:
return view_function(request,*args,**kwargs)
return wraps(view_function,assigned=available_attrs(view_function))(_wrapped_view)
return decorator
hope this helped
edit: made a mistake, put the decorators above the class, they should be in a function inside the class, noticed my mistake almost immediately so hopefully I havent caused any trouble
You can override the get method of your class based view (in this case UniversityUpdateView). Then in the method check if user has rights to access the page and if not raise exception or redirect the user to another page. If the user has enough rights to access the page then just let the normal behavior go on.
class UniversityUpdateView(UpdateView):
model = University
form_class = UniversityForm
template_name='university_form.html'
def get(self, request, *args, **kwargs):
if request.user.groups.filter(name=groupname).count()!=1:
return HttpResponseRedirect("/")
return super().get(request, *args, **kwargs)
I want to add a custom button which will generate a random password using APG in one of the Django models. I'm not sure which template I need to overwrite. Any ideas on how this can be accomplished?
Here is the screen shot of the admin and the other panel where I want to create the button.
Rather than overriding the template, why don't you override the Admin model for your User and the password form and put in the link to generate the password there. The link would likely trigger some javascript that could generate the random password for you, display it, and populate the field. Here's some untested code...
from django.contrib.auth.admin import UserAdmin
from django.contrib.admin.sites import NotRegistered
try:
admin.site.unregister(User)
except NotRegistered:
pass
class CustomUserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomUserForm, self).__init__(*args, **kwargs)
self.fields['password'].help_text = "PUT YOUR CODE HERE"
class CustomUserAdmin(UserAdmin):
form = CustomUserForm
I'm trying to add some kind of generic preview functionality to the Django admin. Opposed to Django's builtin preview-on-site functionality this preview should only be visible to logged in users with specific permissions.
All my content models have the same base class which adds a status like published and unpublished. Obviously unpublished content doesn't appear on the website, but editors should still be able to preview an unpublished site.
I read about class based views in the upcoming Django 1.3 release which might be well suited to implement it in a generic way. With Django 1.2 i can't seem to come up with a solution without touching any single view and adding specific permission checks. Has anyone done something like that before?
I believe the Django Admin already provides a "show on site" option to the admin pages of any models which provides a get_absolute_url() method. Using decorators, it should be possible to do this in a generic way across models
class MyArticleModel(Article): #extends your abstract Article model
title = .....
slug = ......
body = ......
#models.permalink
def get_absolute_url(self): # this puts a 'view on site' link in the model admin page
return ('views.article_view', [self.slug])
#------ custom article decorator -------------------
from django.http import Http404
from django.shortcuts import get_object_or_404
def article(view, model, key='slug'):
""" Decorator that takes a model class and returns an instance
based on whether the model is viewable by the current user. """
def worker_function(request, **kwargs):
selector = {key:kwargs[key]}
instance = get_object_or_404(model, **selector)
del kwargs[key] #remove id/slug from view params
if instance.published or request.user.is_staff() or instance.author is request.user:
return view(request, article=instance, **kwargs)
else:
raise Http404
return worker_function
#------- urls -----------------
url(r'^article/(?(slug)[\w\-]{10-30})$', article_view, name='article-view'),
url(r'^article/print/(?(id)\d+)$',
article(view=generic.direct_to_template,
model=MyArticleModel, key='id'),
name='article-print-view'
)
#------ views ----------------
from django.shortcuts import render_to_response
#article(MyArticleModel)
def article(request, article):
#do processing!
return render_to_response('article_template.html', {'article':instance},
xontext_instance=RequestContext(request) )
Hope this is informative (and hopefully correct ;)