I'm using django as my framework for some web application.
I implemented a modelview of my own because I have a few querysets and seriazliers in the same view.
For this use, I needed to implement all of the CRUD functions myself:
class Models1AndModel2View(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
model1 = Model1.object.all()
model1_serializer_class = Model1Seriazlizer
model2 = Model2.object.all()
model2_serializer_class = Model2Seriazlizer
def refresh_querysets(func):
def inner(self, *args, **kwargs):
value = func(self, *args, **kwargs)
self.model1 = Model1.object.all()
self.model2 = Model2.object.all()
return value
return inner
@refresh_querysets
def list(self, request, *args, **kwargs):
...
@refresh_querysets
def retrieve(self, pk, request, *args, **kwargs):
...
@refresh_querysets
def update(self, pk, request, *args, **kwargs):
...
@refresh_querysets
def delete(self, pk, request, *args, **kwargs):
...
@refresh_querysets
def create(self, request, *args, **kwargs):
...
Notice that I'm calling the decorator's function before the objects refresh. I noticed that every attribute set after the function calls is not actually set.
For example - some test of mine:
- list all the models - 2 models instances
- delete one of them
- list them again - still 2 models instances (in model1 model2)
- if you query the model1 and model2 you can see that one of the instances is deleted as expected, but the model1 was not refreshed.
I changed the order on the inner function of the decorator, and it worked as expected.
def refresh_querysets(func):
def inner(self, *args, **kwargs):
self.model1 = Model1.object.all()
self.model2 = Model2.object.all()
return func(self, *args, **kwargs)
return inner
CodePudding user response:
I believe your issue is because the view is temporary.
You save self.model1
on the view which is destroyed and recreated per request.
There is no point updating the self
if the object will be destroyed.
Also, you should remember that model1
as set in the class variable is initialized on class creation only, and not on instance creation, meaning it will always contain the original data from when you imported that respective module.
There are 3 options to solve it:
Change the order of the function decorator as you've done, setting
self.model1
before running the function, or pass it as a parameter.Change
model1
on__init__
, and so the changes will apply on instance creation.While frowned upon, the class attribute
model1
is right now equivalent to a "class global" (and has almost all of a global downsides). You can simply change it like so:self.__class__.model1 = Model1.object.all()
Keep in mind I do not believe this class attribute should even exist. Should it be immutable, setting it on the instance creation makes more sense.
Either case, I'm not sure if you wish to dump the entire object / DB at every request. I do not know if django smartly caches object.all()
(and updates the cache upon modification), but if it doesn't it'll be a major slowdown.