Get instances during serializer validation in DRF - django-rest-framework

I am starting to work with the Django REST framework for a mini-reddit project I already developed.
The problem is that I am stuck in this situation:
A Minisub is like a subreddit. It has, among others, a field named managers which is ManyToMany with User.
An Ad is an advertising which will be displayed on the minisub, and it has a field named minisubs which is ManyToMany with Minisub. It has also a author field, foreign key with User.
I would like to allow these managers to add some ads on their minisubs through a DRF API. It is actually working. But I want to check that they put in minisubs only minisubs where they are managers.
I found a way like that:
class AdSerializer(serializers.HyperlinkedModelSerializer):
# ...
def validate_minisubs(self, value):
for m in value:
if user not in m.managers.all():
raise serializers.ValidationError("...")
return value
My question is: How to get user ? I can't find a way to get the value Ad.author (this field is set automatically in the serial data according to the user authentication). Maybe I don't find a way because there is no ways ? The place to do this is somewhere else ?
Thanks in advance.

You may get it out of the serializer this way:
class YourModelSeializer(serializers.HyperlinkedModelSerializer):
class Meta:
model=YourModel
def validate_myfield(self):
instance = getattr(self, 'instance', None)
...

I believe that this is a job for the permissions, if you are performing CRUD operations for inserting that into a database then u can have a permission class returns True if the user is a manager.
a permissions instance has access to the request which u can use to get the user and check if he is a manager:
http://www.django-rest-framework.org/api-guide/permissions/#custom-permissions

Related

How to work with not (yet) registered devise Users

I have a User model, for login and registration, its email field is used (everything vanilla from the devise gem).
I want (other) users to be able to e.g. add Users to a team, with the email-address as the identifier.
That is fine when the User is already existing (pseudo #team.users.add(User.find_by(email: other_users_email))) but I am unsure how to handle situations where the user does not yet exist (did not [yet] register).
When a (new) User sets up a new account, for the example above after successfull registration current_user.teams should show up correctly.
I do not want to force these potentially new users to use the system (e.g. using devise_invitable) and bother them with an email.
I followed the path of creating the User when a user with the given email does not yet exist, but then when the user actually tries to setup an account, it fails (email not unique).
Alternatively, I could remodel the TeamMember-part and let it optionally either store an email-adress or the reference to an existing User. Then what I would need is to check for "open" TeamMembers directly after User-Account-creation (so, TeamMembers with the given email). I could also do this on each requst, but that looks too expensive to me. There might be race conditions, but I could live with that (and check for the every-now-in-a-millenia-gap with a cron-job).
Any pointers? I am sure this is not that unusual.
I'd do this:
When a user A adds user B to a team by email, create the object for that user B, but set a flag, something like auto_created_and_inactive: true
When user B signs up on the site, you just have to handle this in your users#create: first, try to find an auto-created record and update it (set a password or whatever; also reset the flag). Or otherwise proceed with the usual route of creating a new record.
I have to admit that I did not yet tried #sergio-tulentsevs approach (implement RegistrationController#create). But to complete what I sketched in my question:
User model can define an after_confirmation method, which is called after ... confirmation! So, if I store every information about a potential user with a reference to his/her email-adress, once he/she registered I can query this information and e.g. complete Team-Memberships.
# app/models/user.rb
def after_confirmation
# (pseudo-code, did not try)
self.teams < TeamMembership.open.where(email: self.email)
end

User has_many posts. Get all users that have at least 1 post

Users have_many posts.
In a view, I want to get an alphabetized list of all users that have at least 1 post. Here is how I currently do it. Is there a way to make this all one line / using better Rails ActiveRecord conventions?
#users.order("name ASC").each do |user|
if user.posts > 0
...
end
end
Your current solution isn't bad (it's a single query) but it can be improved.
You can use ActiveRecord's built-in counter cache functionality to store the number of associated objects on the parent (in this case, the number of posts associated with a user). Then you can craft a query like this:
User.where('posts_count > 0').order('name ASC')
Here are the docs on :counter_cache (taken from here):
:counter_cache
Caches the number of belonging objects on the associate class through the use of increment_counter and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it's destroyed. This requires that a column named #{table_name}_count (such as comments_count for a belonging Comment class) is used on the associate class (such as a Post class) - that is the migration for #{table_name}_count is created on the associate class (such that Post.comments_count will return the count cached, see note below). You can also specify a custom counter cache column by providing a column name instead of a true/false value to this option (e.g., counter_cache: :my_custom_counter.) Note: Specifying a counter cache will add it to that model's list of readonly attributes using attr_readonly.
We can get all the user ids which have atleast one post using this.
Post.uniq.pluck(:user_id);
And then we can fetch all the user as follows.
User.order(:name).find(Post.uniq.pluck(:user_id));
User.joins(:posts).order('users.name asc') will perform an inner join, as described in the documentation here. A counter cache isn't a bad solution either.

django rest frame work tutorial 4 serializer concept

I finished tutorial 1-4 at http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html and got the code run.
However, I am not fully understand the explanation around:
owner = serializers.Field(source='owner.username')
I am confused by which field refering to which field.
1.For example, there is an owner field defined in Snippet class in models.py. After looking it up at https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey, it says ForeignKey() returns a class. Does it return the auth.User class?
2.If it does, what "owner" does the
owner = serializers.Field(source='owner.username')
refer to? I do not found owner in the import part of serializers.py.
3.What does serializers.Field(source='owner.username') returns? Does it return the username in the auth.User?
4.Should we add the corresponding field in a serializer class if the corresponding model has a field reference to another table?
source = 'owner.username' will translate to 'user.username' since owner is nothing but FK-User.
Please note that 'owner' on the left side of field is not important here, in your case. i.e, you can still add custom fields like,
xyz = serializers.Field(source='owner.username')

getting old values of updated domain properties in grails

I am trying to implement the beforUpdate event in grails domain classes I need to audit log both the old and new values of the Domains attributes. I see that we can use the isDirty check or use Domain.dirtyPropertyNames which return list of properties which are dirty in the domain. and getPersistentValue gets the old value in the table so I can have both values..
For implementing this I will be using the beforUpdate event in the domain class and call a logging service from there, passing it the id of the User domain. now using this ID I can get user Instance in Service and then check if any fields are dirty using the above specified method? or do I need to log the Audit when I am actually doing the Update in the UserController's update def?
Which is the better approach?
I want to confirm if this the right approach..
Also what other things I need to take care for, Like:
1) if the attributes are domain object references and not simple types.
2) any other things I need to take care like not flushing out the hibernate session, thinking of implementing this in call to service from the domain class.
Regards,
Priyank
Edit: I tried this in the beforeUpdate event in User domain that I want to Audit log for Update activity..
def beforeUpdate = {
GraauditService service = AH.getApplication().getMainContext().getBean(''graauditService)
service.saveUserUpdateEntry(this.id); // id property of User domain...
}
In the method in Service I do:
def saveUserUpdateEntry(Long id){
User grauser = User.get(id);
println ("user="+ grauser)
println "Dirty Properties -: ${grauser.dirtyPropertyNames}"
println "Changed value for firstName = -: ${ grauser.firstName}"
println "Database value for firstName = -: ${ grauser.getPersistentValue('firstName')}"
}
I try to do the update from the UI for email, firstname, lastname and get the following on console:
user=com.gra.register.User : 1
Dirty Properties -: [eMail, firstName, lastName]
Changed value for firstName = -: sefser
Database value for firstName = -: administer
user=com.gra.register.User : 1
Dirty Properties -: []
Changed value for firstName = -: sefser
Database value for firstName = -: sefser
possible nonthreadsafe access to session
I am not able to know:
1) Why am I getting 2 sets ... is the event called twice once before commit and once after commit...??
2) how to remove or handle the Hibernate exception (tried to use withNew session in the function but no difference
Thanks in Advance..
Rather than using GORM event handlers for audit logging, use audit logging plugin. This will take away a lot of pain of yours.
Hope this helps.
or
If You want much finer control over what you are doing you should consider using a subclass of Hibernate's EmptyInterceptor. This will serve tow purposes for you
Will give you much finer control over what and how you are doing the audit logging
Will place all your logic for audit logging at one place, which will help you maintaining your code.
Click here to see the API for EmptyInterceptor.
Note: Hibernate does not ship any implementation in this class and also don't provide any subclass of this which might provide you the default behavior. So you will have to write a custom implementation.

Axapta: Validate Access to return value from display method

The Dynamics AX 2009 Best Practice add-in is throwing the following error on a display method override.
"TwC: Validate access to return value from the display/edit method."
Here is my display method.
display ABC_StyleName lookupModuleName(ABC_StyleSettings _ABC_StyleSettings)
{
;
return ABC_Styles::find(_ABC_StyleSettings.StyleID).StyleName;
}
I'm assuming it wants me to check a config or security key before returning a result. Any suggestions/examples on where to start?
Thanks
This is a reminder that you need to consider whether the user should have access to the data you are returning from the function. For table fields, the kernel normally does this for you based on the security groups the user is in and the security keys set on fields.
To check if a user has access to a field, use the hasFieldAccess function. To see how this is used, look at the table methods BankAccountStatement.openingBalance() or CustTable.openInvoiceBalanceMST(). There are other helper functions to check security keys such as hasMenuItemAccess, hasSecuritykeyAccess, and hasTableAccess.
In your case, add this code:
if(!hasFieldAccess(tablenum(ABC_Styles),fieldnum(ABC_Styles,StyleName)))
{
throw error("#SYS57330");
}
Even after you add that code, you will still get the Best Practice error. To tell the compiler you have addressed the issue, you need to add the following comment immediatly before the function declaration:
//BP Deviation Documented

Resources