Error when attempting to add an autocomplete field to the AuthUserGroupsAdmin - django-admin

I am attempting to add the default AuthUserGroups as a model to the admin page. It works fine, only I am trying to add an autocomplete field to the user section. When I put it, it gives an error "NoReverseMatch at /admin/Interface/authusergroups/add/"
"Reverse for 'Interface_authuser_autocomplete' not found. 'Interface_authuser_autocomplete' is not a valid view function or pattern name."
class AuthUserGroupsAdmin(admin.ModelAdmin):
search_fields = ['group__name', 'user__username']
autocomplete_fields = ['user']
admin.site.register(models.AuthUserGroups, AuthUserGroupsAdmin)
As a note, the error only comes up when attempting to add a new authUserGroup.
Is there any other way of implementing an autocomplete field within the AuthUserGroups Admin view, or is there a known solution to this error?

You need to tell Django by what field the AuthUser admin should be searchable in the autocomplete field. If you are using the default Django's admin you will need to unregister it and create a new UserAdmin for this use case.
#admin.site.register(AuthUser)
class AuthUserAdmin(admin.ModelAdmin):
list_display = ('email', 'first_name', 'last_name')
search_fields = ['username']
#admin.site.register(AuthUserGroups)
class AuthUserGroupsAdmin(admin.ModelAdmin):
search_fields = ['group__name', 'user__username']
autocomplete_fields = ['user']

Related

rails can you reference a model within a model?

I seem to have run into a problem with trying to use a model in another model in Rails.
I am pulling a list of users from Active Directory with LDAP in a dropdown. I want to parse the cn that I get from Ldap into a firstname and lastname.
The problem I am running into is that I need to find a record in the users model. The parsing is being done in observations.rb.
Observation.rb:
def parse_employee
#emp_name = '' #initialize
self.employee_raw = self.employee_raw[2...-2] # get rid of the quotes and brackets
#emp_name = self.employee_raw.split(' ') # split first/last names
#emp_first_name = #emp_name[0] #Grab the first name
#emp_last_name = #emp_name[1] # grab the surname
#user = User.where("last_name like ?", #emp_last_name)
self.employee_id = #user.id
end
I've played with this quite a bit and it appears that I can't reference other models from within a model.
To sum up, what I am trying to do is
1. Have the user select the appropriate person from a dropdown that is pulled via LDAP from active directory.
2. Use the first and last names to find the appropriate user in my user table (Right now I'm just trying to get it to work with the last name as that is unique enough)
3. When I find the correct user in the user table, enter that id in the employee_id field in my observations table.

Rails set the value of a field based on another field in the same record via Model

I have a table called Contacts. Two of it's columns are called email and maxname. When the Contact is created, I would to set maxname the the text before the # in the email field. So, if a new Contact is jebb#gmail.com, then his maxname should be jebb.
Just for testing I'm trying to put the whole email into maxname (before I figure out how to parse the email text).
So, in the Contacts Model I put this code:
before_create :set_maxname
before_update :set_maxname
protected
def set_maxname
self.maxname = self.email
end
That works. But, how can I parse the self.email so I just get the part before the # ??
Thanks for the help!!
Off the top of my head, doing self.email.split('#')[0] would work.
Edit: Also, the self isn't really necessary in this example. It's explicit, but not required.
Or you could use,
self.email.gsub(/#.*/,'')

django admin permissions to modify model's attributes

we are using django to develop a customer-management application, and we need to set permissions to an agent whether he/she can edit the customer's attributes ().
for example,
if i have a model:
class Customer(models.Model):
# basic information
name = models.CharField(max_length=150) # the name of this customer
date = models.DateField(auto_now_add=True) # the date that this customer is created
# personal information
citizen_id = models.BigIntegerField(blank=True)
phone = models.BigIntegerField(max_length=20, blank=True)
work = models.CharField(max_length=100, blank=True)
address = models.CharField(max_length=300, blank=True)
bank_card = models.BigIntegerField()
# installation detail
primary = models.IntegerField(default=0)
secondary = models.IntegerField(default=0)
region = models.ForeignKey(Region) # the region that this customer currently lives in
type = models.ForeignKey(Type) # the installation type
group = models.ForeignKey(Group)
STATUS_CHOICES = (
('Active', 'Active'),
('Inactive', 'Inactive'),
('Transfered', 'Transfered'),
('Closed', 'Closed'),
('Suspended', 'Suspended'),
('Cancelled', 'Cancelled'),
)
status = models.CharField(max_length=40, choices=STATUS_CHOICES)
and I want to be able to set the permissions for editing some of the fields, but the current permission system only allow you add/change/delete a model instance, where the "change" allows an user to edit all the attributes in that model, which is not what we really want.
user A can edit phone, address, work and citizen_id
user B can only edit phone and address,
user C can edit citizen_id, .....
etc...
and I want to be able to set different permissions
Is it possible to make this happen? It'd be really helpful if I could use the django admin system to manage agents and customers.
=======================
thank you so much for FallenAngel's reply.
I think that's exactly what we want.
this is what I've tried,
in admin.py
class CustomerAdmin(admin.ModelAdmin):
def change_view(self, request, object_id, extra_context=None):
agent = Agent.object.get(user=request.user)
permitted_fields = agent.permitted_fields # assume i have this setup...
self.readonly_fields = get_not_permitted_fields(premitted_fields) # assume I have this function written somewhere
return super(CustomerAdmin, self).change_view(request, object_id,
extra_context=None)
this works exactly that way I want: for the not permitted fields, set them to readonly...
thanks again,
That is possible... You must use django admin methods as they described in here... You must define add_view, change_view and changelist_view functions...
You must also find a way to group users (groups might be a good way, or you can use permissions). I create a model that extends User model, but you can find your own way...
Second write basic add, change and listview founctions like:
class CustomerAdmin(admin.ModelAdmin):
list_display= ["fields that will be used for all users"]
def changelist_view(self, request, extra_context=None):
if request.user == "type a":
self.list_display.extend["list of other fields"]
return super(CustomerAdmin, self).changelist_view(request, extra_context)
You must specify add, change (and changelist if required) views and handle each user type. Then Django will show related fields for the user. You extend list_display, fileds, exclude, list_filter and such django admin field display methods...

remove field name from object validation message

I've got a simple active record validation on an object using this within a form:
form.error_messages({:message => '', :header_message => ''})
This in turn outputs something like "FieldName My Custom message"
What i need to do is remove the field name from the error message but leave my custom message.
Can anyone point me in the right direction for this.
In rails 3.2.6, you can set this in a locale file (e.g., config/locales/en.yml):
en:
errors:
format: "%{message}"
Otherwise, the default format is "%{attribute} %{message}".
One way to have complete control over the messages is to use a custom validate block in the model. e.g. to check that a field is not blank it would be like this:
class MyModel < ActiveRecord::Base
validate do |model|
model.errors.add_to_base("My Custom message") if user.field.blank?
end
end
add_to_base is intended for adding messages that aren't related to a particular individual field (e.g. if a combination of multiple fields is illegal). This means that the CSS to highlight your invalid field won't get added. You can work arround this by also adding a nil message to the errors for your field e.g.
model.errors.add(:field, nil)
Alternatively, check out custom-err-message plugin - this plugin gives you the option to not have your custom validation error message prefixed with the attribute name.
Update:
add_to_base is deprecated since Rails 3. The following can be used instead:
model_instance.errors.add(:base, "Msg")
Ref: https://apidock.com/rails/ActiveRecord/Errors/add_to_base
You can use errors.add_to_base http://api.rubyonrails.org/classes/ActiveRecord/Errors.html#M001712
You can access the object's errors instance directly if you need full control over how the messages are presented.

Rails updating attribute security: use a callback or attr_accessible?

I've got a website model that requires a user to verify ownership of the website.
Thanks to stack overflow, I was able to find the solution for user ownership verification here: Validate website ownership in rails
After the model passes the verification test there is a verified attribute that gets set to true.
The problem I'm running into is when the user wants to edit attributes of his or her website, he or she could easily change the name of the domain while the verified attribute remains true, thus allowing the user to create website objects without verifying ownership.
I can think of two ways to solve this:
1. Have a callback that changes the verification to false if the domain name of the website gets changed.
2. Allow attr_accessible for the domain upon the creation of a new object but not when updating it.
I'm stumped as to how to implement either of these practically.
Callbacks and Active Record Dirty methods are definitely the way to go for this type of situation.
before_update :set_domain_status
def set_domain_status
self.verified = false if self.domain_changed?
end
_changed? can be added to any attribute, returning true if the value has changed from that originally loaded from the database.
I think your Option#1 is the best route. Otherwise you get into the business of trying to reconcile create and update actions - which you would need to do to handle Option #2.
You could override the setter for domain name and then perform custom logic, like so:
In your Model:
def domain=(the_domain)
raise ValidOwnerRequired if verified? && domain != the_domain
# if we got here then the this record is new and this is a creation attempt
#require_domain_verification = true
# do other stuff here..
end
def require_domain_verification?
#require_domain_verification == true
end
And then have an observer for that model:
def after_save(record)
if record.require_domain_verification?
SomeMailer.deliver_domain_verification(record)
end
end
Something like that...
Cody, your answer got me on the right track. Thanks a lot!
This is what I went for in my case:
def domain=(the_domain)
if domain != the_domain
self[:domain] = the_domain
self[:verified] = false
end
end
It works just fine.

Resources