Im trying to check if a value for pid is uniqe but i cant manage to make alluth adapter to find the pid field. Any tips? Nothin happend, but if i change pid value to email the code works on the email field. I cant get the pid field to work whit this function. Maybe im referencing it in a wrong way and the filed does not belong to the default account adaptet-
class PidMaxAdapter(DefaultAccountAdapter):
def clean_pid(self, pid, user):
user.profile.pid = pid
if len(pid) > 9:
raise ValidationError('Please enter a username value\
less than the current one')
# For other default validations.
return DefaultAccountAdapter.clean_pid(self, pid)
Create a custom signup form and do your validation in there.
Here's an example where I have a setting to disable recaptcha
from django import forms
from django.conf import settings
from allauth.account.forms import SignupForm as BaseSignupForm
from captcha.fields import ReCaptchaField
from .widgets import RefreshingCaptchaV3
class SignupForm(BaseSignupForm):
""" Our signup form to integrate captcha """
captcha = ReCaptchaField(
label='',
widget=RefreshingCaptchaV3()
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if settings.DISABLE_RECAPTCHA:
del self.fields['captcha']
You can get allauth to use your custom forms with the following setting;
ACCOUNT_FORMS = {
'change_password': 'apps.accounts.forms.ChangePasswordForm',
'reset_password': 'apps.accounts.forms.ResetPasswordForm',
'signup': 'apps.accounts.forms.SignupForm',
}
If you pass a pid to the form, you can then make it an attribute of the form instance in the __init__ and assign it to the profile during the save. Or have pid as a field, pass it a value in the initial data for the form and have it as a hidden input (forms.HiddenInput() is the widget).
Then in the clean_pid() you could validate that the value is unique against the other rows in the table. Depending on what you're doing with this data, it'd make most sense to use something like a UUID so that you don't have to worry so much about clashing values.
Related
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
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>]
I've read through several similar questions here, but I still can't seem to find a solution:
I am using the django-registration package and I want to make a registration form that does not have an email field, or at least not required. I have tried many different ways, but here is one:
# in forms.py
from registration.forms import RegistrationForm
class ExpRegistrationForm(RegistrationForm):
# email = forms.EmailField(label="E-mail",required=False)
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
self.fields['email'].required = False
Then I link this to a custom view:
# in views.py
from registration.backends.simple.views import RegistrationView as BaseRegistrationView
class ExpRegistrationView(BaseRegistrationView):
form_class = ExpRegistrationForm
Then in urls, after importing views, I add to urlpatterns:
url(r'^../accounts/register/$',views.ExpRegistrationView.as_view(), name='registration_register')
I've shown two attempts above, but I also tried using del or pop to try to get rid of email from my form... And I always get a field error, saying that email is required...
Any suggestions? Or more information needed?
I'm trying to extend Django registration to include my own registration form. In principle this is fairly simple. I just have to write my own form (CustomRegistrationForm) which is a child of the original one (RegistrationForm). Then I can process my specific input by using the user_registered signal of django registration.
So here is what I did:
urls.py:
from django.conf.urls import patterns, include, url
from registration.views import register
from forms import CustomRegistrationForm
from django.contrib import admin
import regbackend
admin.autodiscover()
urlpatterns = patterns('',
url(r'^register/$', register, {'backend': 'registration.backends.default.DefaultBackend', 'form_class': CustomRegistrationForm, 'template_name': 'custom_profile/registration_form.html'},
name='registration_register'),
)
regbackend.py:
from django import forms
from models import UserProfile
from forms import CustomRegistrationForm
def user_created(sender, user, request, **kwargs):
form = CustomRegistrationForm(data=request.POST, files=request.FILES)
if form.is_valid(): # HERE: always fails
user_profile = UserProfile()
user_profile.user = user
user_profile.matriculation_number = form.cleaned_data['matriculation_number']
user_profile.save()
from registration.signals import user_registered
user_registered.connect(user_created)
forms.py:
from models import UserProfile
from django import forms
from registration.forms import RegistrationForm
from django.utils.translation import ugettext_lazy as _
attrs_dict = {'class': 'required'}
class CustomRegistrationForm(RegistrationForm):
matriculation_number = forms.CharField(widget=forms.TextInput(attrs=attrs_dict),
label=_("Matriculation number"),
max_length=12,
error_messages={'invalid': _("This value has to be unique and may contain only numbers.")},
initial=108)
def clean_matriculation_number(self):
print "Validating matriculation number."
data = self.cleaned_data['matriculation_number']
if len(data) != 12:
raise forms.ValidationError(_("Matriculation number consists of exactly 12 digits."))
return data
So the problem is the is_valid() function, because it always returns False. Even if there are no errors! So what is wrong? I spent hours on this one and I have no idea anymore :(
Any help is much appreciated!!
The reason form.is_valid() fails is probably because the form's "clean_username" function checks if the username passed to it already exists. Since the signal is sent after the User object is created and added to the database, the form will fail to pass this test every time. My guess would be if you logged form.cleaned_data after is_valid() returns False, you'll get a list of all of the fields except the username.
form.data might not contain changed values for the fields if the form clean_ function makes any changes (I couldn't find much documentation on form.data).
To avoid the potential problems this might cause, I made two classes for my custom registration form:
# I use this one for validating in my create_user_profile function
class MyRegistrationFormInternal(forms.Form):
# Just an example with only one field that holds a name
name = forms.CharField(initial="Your name", max_length=100)
def clean_name(self):
# (Optional) Change the name in some way, but do not check to see if it already exists
return self.cleaned_data['name'] + ' foo '
# This one is actually displayed
class MyRegistrationForm (MyRegistrationFormInternal):
# Here is where we check if the user already exists
def clean_name(self):
modified_name = super(MyRegistrationForm, self).clean_name()
# Check if a user with this name already exists
duplicate = (User.objects.filter(name=modified_name)
if duplicate.exists():
raise forms.ValidationError("A user with that name already exists.")
else:
return modified_name
Then, instead of using the form.data (which may still be "unclean" in some ways), you can run your POST data through MyRegistrationFormInternal, and is_valid() shouldn't always return false.
I realize this isn't the cleanest solution, but it avoids having to use the (possibly raw) form.data.
Ok I think I solved it (more or less).
I'm still not really sure, why the form did not validate. But as I said I was extending django-registration and the 'register' view already called is_valid() of the form, so I can assume that the form is valid when I process the posted data any futher. The view then calls the backend
backend.register(request, **form.cleaned_data)
with the request and the cleaned data (which is just username, email and password). So I can't use it for registration because my additional information is missing. The backend then fires the signal that I am using and what I did is, is that I created the form again with the provided request. This form, however, will NOT validate (and I tried everything!!) I looked it up, I am doing the exact same thing as django-registration, but it's not working in my code.
So I did not really solve the problem, because the form is still not validating. But I found peace with this, when I realized that the form was already validated by the 'register' view. So I am using form.data[..] instead of form.cleaned_data[..] now which shouldn't be a problem...
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