How to know the user who created a specific item in Django? - django

Is it possible to get the id of the user who created a specific item, no matter what it, in Django? I have a site where when the users are authenticated can access a form and submit a new item. Can I retrieve who created what without adding an extra 'submitted by'
Event.objects.filter(owner=self.kwargs['pk'])
(which gives me name 'self' is not defined )?

You cannot access the information without adding a new field, but you can have a look at this library django-audit-log for easy tracking. It will add created_by and modified_by fields and maintain them.

Related

what on_delete option to use in django app?

I have an Article model that allows admins to publish articles. Each article is assigned to a user that is creating this article.
I want to make sure that all articles will stay untouched even if I delete the author of this particular article. I chose on_delete=models.DO_NOTHING to be sure that nothing except user account will be removed but I am not quite sure that is the most effective way.
class Article(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, blank=True, null=True, on_delete=models.DO_NOTHING)
title = models.CharField('Title', max_length=70, help_text='max 70 characters')
body = models.TextField('Description')
Question
Should I use another option to use or DO_NOTHING is good enough. Obviously the most important to me is that author's name will be visible in the article after deletion and the article itself cannot be removed.
Best I can say is:
add another field called author_name.
now set the on_delete of your author to models.SET_NULL.
Add a custom save method to add the name of your user to author_name.
Add a property to your model named author_full_name
in this property check if author is not null return user name and last name.
if author is None return author_name.
This way when the article is saved user full name is saved on author_name. and if user is deleted you can use the author_name.
but watch out for the custom save method it might add some issues if you don't check the user and it's deletion.
Edit: Another solution
If you have a custom user model you can a field to your users called is_deleted.
After your users delete their accounts just set this field to True and have the logic in your app to excludes deleted accounts.
this way your users won't be accessible to anyone but you can use them for the articles and foreign keys. (remember to tell your users that account deletion works this way or set a task to remove accounts after a while and set the field that I said above.)
Basically the database table creates record in certain table and stores user info as I can see you are linking article model with user based on User model.
There can be two cases like if you want the article to remain in database even if you delete the author you will get article when the article gets displayed somewhere.
If you do Cascade delete it deletes article record when associated author gets delete.
If you do models.Protect you wont get access to delete article when you user is deleted.
coming to your very models.Do nothings is a bad idea since this would create integrity issues in your database (referencing an object that actually doesn't exist). SQL equivalent: NO ACTION
find more here.
You just need to use CASCADE as below:
on_delete=models.CASCADE

Confusion in id parameter in django

I was making an E Commerce website and added various products in it. Now for making a cart i made a add to cart button. And in HTML i assigned an id to this button. The id was pr{{product.id}}. I have not made buttons individually for every item. There is a for loop running which creates buttons. Now My doubt is that i have not assigned any field id in the models class. But still this code is running and when i printed the id's on the console i realised that it prints like pr32, pr33, pr34 ie in a sequential manner. So is there any product.id field predefined in django??
My doubt is that I have not assigned any field id in the models class.
You don't need to. If you do not add a primary key yourself, Django will add a field with the name id that is an AutoField. This is documented in the Automatic primary key fields section of the documentation:
By default, Django gives each model the following field:
id = models.AutoField(primary_key=True)
This is an auto-incrementing primary key.
If you’d like to specify a custom primary key, specify
primary_key=True on one of your fields. If Django sees you’ve
explicitly set Field.primary_key, it won’t add the automatic id
column.
Each model requires exactly one field to have primary_key=True
(either explicitly declared or automatically added).
So to answer your question:
So is there any product.id field predefined in django?
Yes, if you did not specify a field with primary_key=True yourself.

How to check if notification has been viewed like in facebook?

Whenever there are facebook notifications a red indicator appears until the notifications have been viewed for the first time.
How could I implement something similar on my site (preferably with django if anything needs to be done server-side)?
The simplest approach would be:
Have a field in the models for viewed_at which is nullable. Once viewed, set the date. If no value is set, that means the user has not viewed it yet.
If there are multiple users whom this feature needs to be extended to, have a foreign key reference:
class MyViewableObject(models.Model):
#fields
class MyViewableViewedBy(models.Model):
user = models.ForeignKey(User)
viewable = models.ForeignKey(MyViewableObject)
Now, when MyViewableObject is viewed, in the view method, create an association for the request.user in the MyViewableViewedBy model.
The user has not viewed if there is no corresponding user entry for the object in the model MyViewableViewedBy

Django: How can I let the user define semantic relations between objects?

In mediawiki, a user can link to a page by just entering the [[Name of the Page]]. In semantic mediawiki, a user can make a semantic relationship to a page by identifying [[example::Some Page]] as an example page.
I want to be able to do this with django models.
For example, I want a user to be able to write a description for a Task object in a workflow app, and put something like "Follow up with [[User.id:43]]."
I'd also love to be able to do the semantic thing.
Finally, I'd like to be able to look at User 43 and see what models link to it.
Is there a django package that will do some or all of this? If not, what is this methodology called generally?
First of all, I'd set up the following to handle link detection and creation:
Create a ModelForm to receive the user's submitted Task. Create a custom validator to operate on the description field of this form. This validator would check that any links entered by the user correspond to the the [[:]] format you've specified.
Override the save method on the Task model. This is a good time to inspect the contents of the description and create links as appropriate.
Side note: I would wrap the view function handling this request in a #transaction.commit_on_success decorator so that either the model and all the links get created, or nothing at all gets created.
Now, in the save method, the real action is happening. I would use a regex to pull out all the links and then work through them one by one.
For each link, you need to determine the model linked to. This would be easy with a dictionary of models keyed on their names.
You need to determine if the link has actually identified a valid model instance. If not, either skip this link or raise an exception and eject from the whole process (see above regarding transactions).
You need to create the links. See below.
Django has a standard mechanism for generic foreign keys which you should definitely consider using here. You could create a link class something like:
class Link(models.Model):
# link to particular task:
task = models.ForeignKey(Task)
# these three fields together set up a generic foreign key which
# represents the object you're linking to:
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
Your Task model objects would then automatically get an attribute called link_set which would be a list of Link instances.
Creating a link would look something like:
# encountered a description with [[User:43]]
instance = User.objects.get(pk=43)
link = Link.objects.create(task=my_task_object, content_object=instance)
By giving Link's content_object attribute an instance of another model, its content_type and object_id fields are automatically filled in for you, and your link will resolve back to that specified instance.
Hope this is helpful. Ask for more detail if you need it.

Implement auto_current_user_add when using Django's User table

I have an AppEngine app that I'm migrating to run in Django, using app-engine-patch to get all the goodness of Django - particularly the Admin interface.
One of my models looks like (partially) this:
class Request(db.Model):
requestor = db.UserProperty(auto_current_user_add=True)
When I display a form based on this model I don't display the requestor field, and so when I call the Model's put() method the entity I'm saving doesn't have the requestor property set. This triggers the auto_current_user_add magic, and the user who created the request is automatically added.
Under Django, I'm using the provided Users table. I want this to display as a list of the users of my app, so the model becomes:
from ragendja.auth.google_models import User
class Request(db.Model):
requestor = db.ReferenceProperty(User)
However, this breaks the auto_current_user_add magic in the admin interface - if the user of the admin interface doesn't enter a value for the requestor property, Django sets the property to None, when I'd really like for the Request to have their username inserted automatically.
How can I restore the magic?
My solutions relies on three things:
First: it's possible to override the model's put() method.
Second: users.get_current_user() still provides the correct user, and
Third: ragendja.auth.google_models.User.get_djangouser_for_user() takes a google.appengine.api.users.user object and returns the corresponding Django User object - creating it first if it didn't already exist.
Putting this all together, I have:
class Request(db.Model):
requestor = db.ReferenceProperty(User)
def put(self):
if not self.requestor:
self.requestor = User.get_djangouser_for_user(users.get_current_user())
super(Request, self).put()
This works nicely with the admin interface: the admin can assign any existing user (or use the supplied + sign to create a new user) - if they leave it blank, they'll be assigned as the requestor.
Later when I add a view for users to manage their own requests, this value will be on the 'excluded' list, and the same method will add in their username every time they create a new request.
I'm not sure if this is an optimal solution though; I'm new to Django, so maybe there's a better way to achieve this.