I want to exclude some fields in my inline based on my request user.
I know somehow I can handle this with methods like 'get_formsets', 'add_view', 'change_view', but I'm not sure what the syntax is.
Any suggestions?
I achieved what I needed with the next code in my inline class:
def get_formset(self, request, obj=None, **kwargs):
if request.user.groups.all().count() > 0:
if request.user.groups.all()[0].name == 'User Group Name':
kwargs['exclude'] = ['field_to_exclude',]
return super(MyInline, self).get_formset(request, obj, **kwargs)
The answer to this question gave me the hints: different fields for add and change pages in admin
There's also the get_exclude hook:
class FoodInline(TabularInline):
model = Food
def get_exclude(self, request, obj=None):
group = request.user.groups.first()
if group and group.name == 'User Group Name':
return ['field_to_exclude', ]
return self.exclude
Related
What is the proper way to pass the parameters to a function?
For example:
def self.find_by_example(username, email)
user = User.find_by_username(username) || User.find_by_email(email)
end
I would like to find the user by his username or email but if a create a function passing the 2 parameters Rails shows
(wrong number of arguments (given 1, expected 2))
When I call User.find_by_example('example')
I still don't get it, the parameters passed in must not be the attribute?
and why does it say "given 1"?
You must be calling the function like `User.find_by_example("name to find") and the function expects two arguments (name and email). You could define the function as:
def self.find_by_example(term)
user = User.find_by_username(term) || User.find_by_email(term)
end
And call it User.find_by_example("Name to find") or User.find_by_example("email#to_find.com")
This does not work ok if you have users with a username like an email. And it is not much efficient if you wish to search by other fields. SO you could also:
def self.find_by_example(terms)
if terms[:email]
user = User.find_by_email(terms[:email])
elsif terms[:username]
user = User.find_by_username(terms[:username])
elsif terms[:id]
user = User.find_by_id(terms[:id])
elsif terms[:document]
user = User.find_by_document(terms[:document])
end
end
And call the method User.find_by_example(:email => "email#example.com"). This is similar to the find_by method that Active Record already provides (but allows many arguments), so no need to implement it.
The proposed and accepted answer is not really the equivalent of the code asked in the question. It is accepted, so one might assume that it guessed the OP intent correctly. But I think it can be useful for (especially junior) programmers to think about the problem more deeply.
Think of what method should do
(not just if it immediately gives you result you wish to see, there can be surprises in the edge cases)
The original code
def self.find_by_example(username, email)
user = User.find_by_username(username) || User.find_by_email(email)
end
Could be used this way x.find_by_example(nil, 'test#example.com').
If we assume there can't be users with NULL username (which IMO is a reasonable assumption), the call would result in finding an user strictly by email.
The proposed solution does not give you this possibility:
def self.find_by_example(term)
user = User.find_by_username(term) || User.find_by_email(term)
end
x.find_by_example('test#example.com') would return user with such username if exists, and (possibly other) user with such e-mail otherwise.
In other words - you have less control which field is used to find a user (which can be correct, if that's really what you need)
So it depends on the OP intent.
If one want to retain how the original method works, but improve the interface, it could be done like this:
def self.find_by_example2(username: nil, email: nil)
user = User.find_by_username(username) || User.find_by_email(email)
end
And calling x.find_by_example2(email: 'test#example.com') is equivalent to x.find_by_example(nil, 'test#example.com') but looks better.
Bonus: Performance implications
The proposed solution
def self.find_by_example(term)
user = User.find_by_username(term) || User.find_by_email(term)
end
makes second query when the user is not find by username. You can improve it as well if you wish to employ some sql magic:
def self.find_by_example(term)
user = User.where("username = ? OR (username IS NULL and email = ?)", term, term).first
end
There's another possibility (though not 100% equivalent to the accepted solution):
def self.find_by_example(term)
user = User.where("username = ? OR email = ?", term, term).first
end
(I'll leave as an exercise the answer how those are different, to keep this post short...ish)
Bonus 2: flexibility
This
def self.find_by_example(terms)
if terms[:email]
user = User.find_by_email(terms[:email])
elsif terms[:username]
user = User.find_by_username(terms[:username])
elsif terms[:id]
user = User.find_by_id(terms[:id])
elsif terms[:document]
user = User.find_by_document(terms[:document])
end
end
is a waste of your time, because rails gives you already better interface to do this.
Instead of calling
x.find_by_example(document: 'foo')
you could just do
User.find_by(document: 'foo')
There's really no need to implement it that way, it's basically crippled version of ActiveRecord interface, that you have to maintain as you add new fields to User model.
We need to implement custom filters for categories in spree ecommerce in latest version as seen here https://github.com/spree/spree .
We need to do it in a dynamic way because we have about 100 filters or more to make. The ideal solution would be to show all available filters in admin area and admin can activate/deactivate them for each category.
Current Scenario:
We know how to make a new filter and apply it. But it takes about four methods per filter as shown in the product_filter.rb file linked below.
Some links we have found useful:
https://gist.github.com/maxivak/cc73b88699c9c6b45a95
https://github.com/radar/spree-core/blob/master/lib/spree/product_filters.rb
Here is some code that allows you to filter by multiple properties. It is not ideal (no proper validation etc) but I guess it is better than doing multiple "in" subqueries.
def add_search_scopes(base_scope)
joins = nil
conditions = nil
product_property_alias = nil
i = 1
search.each do |name, scope_attribute|
scope_name = name.to_sym
# If method is defined in product_filters
if base_scope.respond_to?(:search_scopes) && base_scope.search_scopes.include?(scope_name.to_sym)
base_scope = base_scope.send(scope_name, *scope_attribute)
else
next if scope_attribute.first.empty?
# Find property by name
property_name = name.gsub('_any', '').gsub('selective_', '')
property = Spree::Property.find_by_name(property_name)
next unless property
# Table joins
joins = product if joins.nil?
product_property_alias = product_property.alias("filter_product_property_#{i}")
joins = joins.join(product_property_alias).on(product[:id].eq(product_property_alias[:product_id]))
i += 1
# Conditions
condition = product_property_alias[:property_id].eq(property.id)
.and(product_property_alias[:value].eq(scope_attribute))
conditions = conditions.nil? ? condition : conditions.and(condition)
end
end if search.is_a?(Hash)
joins ? base_scope.joins(joins.join_sources).where(conditions) : base_scope
end
def prepare(params)
super
#properties[:product] = Spree::Product.arel_table
#properties[:product_property] = Spree::ProductProperty.arel_table
end
I want to create a custom view in django admin that mirrors a change form from another model. I've got as far as creating a custom model admin class, and don't know where to go from here. I cant find any good examples for Django 1.8 on how to create a custom admin view.
Django Version: 1.8
class CustomerProductOrderAdmin(admin.ModelAdmin):
review_template = 'admin/onlineordering/order_template.html'
def get_urls(self):
urls = super(CustomerProductOrderAdmin, self).get_urls()
my_urls = patterns('',
(r'\d+/customer_template/$', self.admin_site.admin_view(self.customer_template)),
)
return my_urls + urls
def customer_template(self, request, id):
product_orders = CustomerProductOrder.objects.get(pk=id)
return render_to_response(self.review_template, {
'quantity': 'Quantity: %s' % product_orders.quantity,
}, context_instance=RequestContext(request))
I have a customer table that belong to this user table.
class Customer(models.Model):
customer = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to={'groups__name': "customers"})
/app/model/1 #pk = customer.id
The custom form will have this URL
/app/customform/
When the logged in user goes to /app/customform, they should not see the change form from /app/model/1. They should not see other users change forms. Also, I would like to limit access to the custom form, to a particular group of users. ie this group cannot see /app/model/ but can see /app/customform.
An example for how to add an independent template to admin page
At the model.py file inside the model class add a function
def version_summery(self, ):
batch_d= {}
fy = {}
for br in self.batchresult_set.all():
batch_d[br.name.strip()] = br.__dict__
fy['batch_d'] = batch_d.values()
x = render_to_string('admin/results/result_build_summary.html', fy)
return x
make sure the urls.py knows how to find the template 'result_build_summary.html'
and in the admin.py
readonly_fields = ( 'version_summery',)
fieldsets = (
('', {
'fields': ( 'version_summery', ),
}),
)
I've seen various answers to similar questions, but not for this specific case:
I have a Grails gsp with several fields and a submit button. I want to enter a value in the first field, click submit, and have the controller return values into the remaining fields (including the original entry field). I want to do this with a simple page refresh (no AJAX) and it does not involve a database. I have it working fine with two gsp pages that are identical but have different names. I just call the first one, enter the value, and have the submit action point to the second. But I would like to be able to do it with a single gsp. A simplified version of my controller looks like this:
class CalculatorController {
def index = {
redirect(action: "input")
}
def input= {}
def calculateValues = {
def inputString = params.enterValue
def value2 = 'You entered something on the page'
[field1: inputString, field2: value2]
}
}
you need to have all of logic inside of the same closure if you want to use only one gsp. Test if the params are passed in and return the correct vals
Actually you don't need to have all of your logic in the same closure. Simply specify the view template to use in calculateValues...
def calculateValues = {
def inputString = params.enterValue
def value2 = 'You entered something on the page'
render(view: 'input', model: [field1: inputString, field2: value2])
}
By using the render method you can have multiple controller action reuse the same gsp view.
I have admin user with following five roles[ROLE_ADMIN,ROLESWITCHUSER,ROLE_DOCTOR,ROLE_USER]
and some normal users with only one role i.e ROLE_USER ,now my question is how can i get only normal users from my secuser table i tried with somne iterations
def roleId=SecRole.findByAuthority("ROLE_USER")
userInstance = SecUserSecRole.findAllBySecRole(roleId).secUser
here i got userInstance with all users along with adminuser now i tried to elminate adminuser from my userInstance and saved it in selectUserMap but am getting result for sometime and sometimes its giving all users. I think the sort() function not sorting the userinstansce roles please help me
for(int i=0;i<userInstance.size();i++)
{
println( "am in loop "+i+userInstance[i].username+"roles"+userInstance[i].getAuthorities())
def x=(userInstance[i].getAuthorities().sort())
for(a in x )
{ //println(a.getAuthority())
if((a.getAuthority() == use))
abc=true
else
abc=false
if((a.getAuthority() == adm))
{
println("break")
break;
}
abc=(abc && (a.getAuthority() == use))
if(abc)
{
println("am in true if ")
selectUserMap.add(j,userInstance[i])
j=j+1
}
else
{
println("am in else")
}
}
}
println("==============all users "+selectUserMap)
One thing that would help is to use hierarchical roles - see section "14 Hierarchical Roles" at http://grails-plugins.github.com/grails-spring-security-core/docs/manual/ - and then you wouldn't grant ROLE_USER to anyone but "real" users. If you define your hierarchy like this:
grails.plugins.springsecurity.roleHierarchy = '''
ROLE_ADMIN > ROLE_USER
ROLE_DOCTOR > ROLE_USER
ROLE_ADMIN > ROLE_DOCTOR
'''
then you don't need to explicitly grant ROLE_USER in the database to either a doctor or an admin, but the role will be inferred as granted. Then your original query will work:
def userRole = SecRole.findByAuthority("ROLE_USER")
def usersWithUserRole = SecUserSecRole.findAllBySecRole(userRole).secUser
If you can't or don't want to do this, then you should use a proper database query. It's extremely and unnecessarily expensive to load every user and every user's roles from the database and filter them out in your application. Use this HQL query:
def userRole = SecRole.findByAuthority("ROLE_USER")
def users = SecUserSecRole.executeQuery(
'select u from SecUser u where ' +
'(select count(ur.user) from SecUserSecRole ur where ur.user=u)=1 and ' +
'(:r in (select ur.role from SecUserSecRole ur where ur.user=u))',
[r: userRole])
Oh, you've choosen really complicated way, can understand your algorhitm :( Maybe this is enough:
List selectUserList = userInstance.findAll {
List roles = it.authorities*.authority
return roles.contains('ROLE_USER') && !roles.contains('ROLE_ADMIN')
}
I guess you can build selectUserMap from this selectUserList list (can't understand where you get j)
PS maybe it's better to rename userInstance to userInstances, because it's a list actually, not one instance?