See if Django form submission came from the admin - django

I'm new to django, so I apologize if this has been asked. I'm using the post_save signal to run a task when a new object is created. I need to be able to check if the form was submitted from the admin page or if it was submitted on the live website, is this possible? Where might I find documentation on this?

post_save is too late in the process to log or take action on the source of the object.
post_save is a signal sent from the database/ORM, i.e. it is what is called after a save is done. Does the save function take any input about the source? No. Does that function put anything into the ORM or the database about the source? No.
You want to take whatever action it is in the view function where this occurs. Here is the simplest way to do it that I can think of. I shall assume that your preferred choice of action is to save where it was created in the database.
Consider the following:
class YourObject(models.Model):
name = models.CharField(max_length=30)
creation_location = models.CharField(max_length=30, default="Admin")
Here we have an object with a name and a creation_location, the purpose of the second being to tell where the object is created. To prevent any need to edit the Admin functionality, as that can be a pain, the default value is set to Admin.
Onto the view:
def create_model_view(request):
your_object = YourObject.objects.create(name='FirstObject', creation_location="View")
Here we have a view with a create function for the object. In the initialization, the default value of Admin for the creation_location is overwritten and set to View.

Related

Django REST - Trigger action when updating a model in a REST-friendly way

I have the following use case that I want to implement:
an LMS app powered by DRF has an Exam model, which has a state field which can either be DRAFT or PUBLISHED.
When a teacher publishes an exam, I want them to have the option to also create an announcement on the course (there a model called Announcement for that).
I'm looking for an elegant and efficient way to encode and utilize the information of whether the user wants to contextually publish an announcement when publishing an exam.
This requires identifying three steps:
how to encode whether the user wants to publish the annoncement in a REST request to publish the exam
how to intercept when an exam is being published to optionally publish an exam
how to pass the information about whether the user wants to publish an announcement over to whichever part of the application will be responsbile for actually publishing it.
For the second step, I decided to go with the django-lifecycle package.This beatiful package allows defining a method on the Exam model class itself to look something like:
#hook(AFTER_UPDATE, when='state', is_now=PUBLISHED)
def on_publish(self):
# ... logic
As per the rest, here's two possible solutions I've thought of, which I'd like some feedback on:
define a boolean field publish_announcement on Exam. Inside of the update request for the exam, together with the other payload fields, the frontend will be able to either set that to true or false. Then, in the handler for the exam update, I can do something like:
#hook(AFTER_UPDATE, when='state', is_now=PUBLISHED)
def on_publish(self):
if self.publish_announcement:
publish_announcement(...)
self.publish_announcement = False
self.save()
The upside of this method is that it's trivially easy to pass the information of whether, for a given update request, the user wants to trigger the task of publishing an announcement---all they have to do is put that into the PUT/PATCH request made to the exam. There's also no additional code to handle that information as it's just a field on the model.
The downside is that I'm actually using up a column to store something that isn't a db information at all. As you can see, I'm resetting the value of that field as soon as I'm done updating (this is done to prevent subsequent updates to unintentionally trigger announcement publishing): all I really want to do is pass that information to the AFTER_UPDATE hook and then throw it away.
use a field on the Exam model class which isn't actually a Django field. The idea is that, when receiving an update request, the user could state they want to trigger announcement publishing via, say, a query param. The view would check for the existence of this query and, if truthy, would set a field on the Exam model. The difference here is that the field isn't saved to the db, it's just a class instance field created on the fly and thrown away as the object is disposed of. The hook method could just test that field similarly, this time without having to reset its value at the end because the model doesn't have such a field.
This has the advantage of not having to create db fields which aren't used as real fields, but it adds the need for some "glue" code that adds the temporary field on the model based on the request params.
Can you think of a better alternative?

Django adding new attribute to WSGIRequest

Hey im kinda new to Django and the whole Views/Request process.
So I noticed i got the auth_user inside the request object due to the User middleware I had inside the settings file, and anywhere i have the request, i can call the user object with request.user
I kinda have a similar modal/object that is pretty important and I saw how to create a basic middleware but I'm not for sure how to replicate similar functionality where I'd be able to access that specific object inside the request like "request.object"
Edit: Okay i figured it out, but now the question is how do i reinitialize the process request in a view based on different conditions.
For example:
It starts off as a default of
def process_request(self,request):
request.object = Object.objects.get(id=1)
But based on a specific thing that happens in the views, i want it to change to a different id?

To use signals or override model save method?

Simple use case:
After a user updates a record, I want to get the changed fields and save them in a history table. I'm using django-ditryfields to grab this history. So my thought process was to use the pre_save signal to grab all the 'dirty' fields and them store them in my history table.
Problem there is that I can't get request.user while using signals. I need this to see which user has made the change to the record. My other thought was just to override the save method of my model but then I also can't get request.user from a model directly either. I would have to send a **kwarg['user'] with the user info from the view to get this info. This is fine but I am going to be making save calls from a bunch of different places around the code. I don't want to have to keep passing request.user every time I edit an object. This is why I'd love to have one spot, like a signal, to handle all of this. Perhaps some middleware I'm not familiar with?
Is there a better way to achieve such a thing?
You cannot access the user object from a signal.
You can consider using this third party package: django-requestprovider to access the request object in the signal.
The other way would be to overriding the models' save method.

Django - How to trigger an action when a specific model is saved?

I have two models. One called MainModel and other called HistoricMainModel. I would like to INSERT automatically a row in the HistoricMainModel every time I data is inserted to MainModel. What is best/correct way of doing this in Django?
Best Regards,
If you already have some custom save().-magic going on I would recommend using a post_save() signal or a pre_save() which ever would work best for you.
in your models.py
#receiver(pre_save, sender=MainModel)
def save_a_historicmodel(sender, **kwargs):
#do your save historicmodel logic here
or
def save_a_historicmodel(sender, instance, created, **kwargs):
print "Post save was triggered! Instance:", instance
signals.post_save.connect(save_a_historicmodel, sender=MainModel)
This works so that every time your MainModel is saved this signal is triggered.
Docs here
Rewrite save method in MainModel model to create and insert the HistoricMainModel object before calling the "real" save method.
You could implement this yourself but the best way would be to use an application that does this - like reversion - a django app that implements model history/roll back automatically.
In addition to whatever you will implement, reversion will provide you with:
Integration with the admin backend.
A API to add meta-data to your versions and to revert back to previous versions of your model.
It is a lot more flexible and is widely used and implemented.

Can I create a OneToOneField that will create an object if it does not exist?

I am working with a Django model that looks like this:
class Subscription(models.Model):
user = models.OneToOneField(User)
That is, it has a one-to-one association with the User class from Django's auth module. This association is not optional; however, thanks to some legacy code and some manual tinkering with the database, there are cases in which a user does not have an associated subscription, which means that code like this:
sub = user.subscription
will throw a DoesNotExist exception. However, much of the codebase assumes that every user has an associated Subscription object.
Is there a way I could subclass OneToOneField such that, if the associated Subscription object does not exist in the database, I will create one and return it when user.subscription is called, instead of throwing an exception?
The correct way to do this is to catch the post_save signal, creating an object if necessary.
Add a property named subscription and in getter create necessary reference, for that you may have to do monkey-patching, better alternatives are
refactor your code and add a utility function to get subscription
refactor your code and add a proxy model for User
Just fix the db once