I have some page elements that don't change often and are displayed on every page like some adbars, footer content and such.
I want to change settings for this elements in my admin interface, so I have models for them.
Is there a best practice in django to deal with these elements?
Not really, no. You're describing a singleton pattern, so you might want to implement a singleton model type:
class SingletonModel(models.Model):
class Meta:
abstract = True
def save(self, *args, **kwargs):
self.id = 1
super(SingletonModel, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
pass
That will ensure that any model that inherits from that class can only ever have one member and that it can't be deleted. Other than that, I would suggest combining everything into just one model called something like SiteSettings with fields for header, footer, etc, instead of separate model for each.
You could use a context processor to add them to the context and use a simple caching mechanism so you don't have to hit the db every time like, http://eflorenzano.com/blog/2008/11/28/drop-dead-simple-django-caching/
Hard to answer - what exactly are you asking?
You can display these models in your base template. You can use caching to cut down on database calls.
Related
I want to implement kind of row level security for my model in Django. I want to filter out data as low as it's possible based on some requirement.
Now, I know I could create specified managers for this model as docs says but it seems for me that it needs to be static. I also know that I can create just method that will return queryset as I want but I'll be not sufficient, I mean the possibility to just get all data is still there and the simplest mistake can lead to leak of them.
So I found this post but as author said - it's not safe nor pretty to mess around with global states. This post is nearly 10 years old so I hope that maybe someone has come up with a better generic solution.
Here is piece of example to visualise what I need:
models.py:
class A(models.Model):
...
class B(models.Model):
user = models.ForeignKey(User)
a = models.ForeignKey(A)
And I want to create global functionality for getting objects of A only if instance of B with user as logged in user exists.
I came up with solution to just override get_queryset() of A manager like so:
managers.py
class AManager(models.Manager):
def get_queryset(self):
return super().get_queryset(b__user=**and_here_i_need_a_user**)
but I can't find hot to parametrize it.
==== EDIT ====
Another idea is to simply not allow to get querysets of A explicitly but only via related field from B but I can't find any reference how to accomplish that. Has anyone done something like that?
So you're sort of on the right track. How about something like this...
class AQuerySet(models.QuerySet):
def filter_by_user(self, user, *args, **kwargs):
user_filter = Q(b__user=user)
return self.filter(user_filter, *args, **kwargs)
class AManager(models.Manager):
queryset_class = AQuerySet
def filter_by_user(self, user, *args, **kwargs):
return self.get_queryset().filter_by_user(user, *args, **kwargs)
class A(models.Model):
objects = AManager()
# ...
then you can use it like this:
A.objects.filter_by_user(get_current_user(), some_filter='some_value')
There are several models in my django app. Some of them derive from models.Model, some - from django-hvad's translatable model.
I want to log every save/delete/update operation on them. I am aware of standard django logger of admin actions, but they are too brief and non-verbose to satisfy my needs.
Generally speaking, one common way to achieve this is to define super-class with these operations and extend each model from it. This is not my case because some of my models are translatable and some are not.
Second way are aspects/decorators. I guess, python/django must have something like that, but I don't know what exactly :)
Please, provide me with the most suitable way to do this logging.
Thanks!
You could write a mixin for your model.
import logging
class LogOnUpdateDeleteMixin(models.Model):
pass
def delete(self, *args, **kwargs):
super(LogOnUpdateDeleteMixin, self).delete(*args, **kwargs)
logging.info("%s instance %s (pk %s) deleted" % (str(self._meta), str(self), str(self.pk),) # or whatever you like
def save(self, *args, **kwargs):
super(LogOnUpdateDeleteMixin, self).save(*args, **kwargs)
logging.info("%s instance %s (pk %s) updated" % (str(self._meta), str(self), str(self.pk),) # or whatever you like
class Meta:
abstract = True
Now just use it in your model.
class MyModel(LogOnUpdateDeleteMixin, models.Model):
...
# Update/Delete actions will write to log. Re-use your mixin as needed in as many models as needed.
You can re-use this mixin again and again. Perform translation as you wish, set some attributes in your models and check for them in the mixin.
Which option is best, 1 or 2?
1.
class TopicForm(forms.Form):
name = forms.CharField(required=True)
body = RichTextFormField(required=True)
def save(self, request):
t = models.Topic(user=request.user,
site=get_current_site(request),
name=self.cleaned_data['name'],
body=self.cleaned_data['body'])
t.slug = slugify(self.name)
t.body_html = seo.nofollow(seo.noindex(self.body))
t.ip = utils.get_client_ip(request)
t.save()
or 2.
class Topic(models.Model):
...
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.body_html = seo.nofollow(seo.noindex(self.body))
self.ip = utils.get_client_ip(request)
super(Topic, self).save(*args, **kwargs)
The difference is that the first version is only applied when modifying objects through the form, while the second is applied whenever the model is saved (though that is still a subset of all the ways in which database rows can be modified in Django). Even if you currently only create objects through forms, I think it's still a useful distinction to keep in mind.
It looks to me like a mixture of the two makes sense in your case. A slug is something that you will always want to set based on name - that is, it's inherent to the model itself. On the other hand, the idea of a client_ip seems inexorably tied to the notion of creating an object with a form via a web request.
Of course, you are in a better position to know about the specifics of this model, but that is the general way I would approach the question.
It depends. If this should be applied to every models, then it is better in the model. It will assure you that every Topic object will have correct values, even those you are edited from the admin interface.
The form should be use only to check data from the user and the model is appropriate to automatize this kind of task (generate data before saving the object). Be careful, this shouldn't raise Exception or invalidate data however.
Personally I would prefer the second option. The model should define the business logic too, while forms should just handle user I/O. This way your application will keep consistent even if used in a programmatic way (imported and called from other code).
You shouldnt use 2. its better to use a signal like pre-save or post-save
Source: https://docs.djangoproject.com/en/dev/topics/signals/
#receiver(pre_save, sender=Topic)
def topic_pre_save_handler(sender, instance, **kwargs):
instance.slug = slugify(self.name)
instance.body_html = seo.nofollow(seo.noindex(self.body))
instance.ip = utils.get_client_ip(request)
I would like to solve the following situation.
I have a side panel containing information of the active user. For this an instance of UserInfo model needs to be passed to the views.
Additionally, I would like to pass a number of other model instances to the pages (eg. Purchases, Favourites, etc.).
I know this is pretty easy to do by overriding the get_context_data.
def get_context_data(self, **kwargs):
kwargs['purchases'] = Purchases.objects.get(id=1)
kwargs['favourites'] = Favourites.objects.get(id=1)
.... etc
return super(UploadFileView, self).get_context_data(**kwargs)
So my question is - what would be the best/most appropriate CBV to use for this?
This isn't quite a DetailView as you have multiple objects, but it isn't a ListView either, nor does it look like a FormView or its children.
Since you gain nothing from those, a simple TemplateView is probably the way to go.
If you are querying the same UserInfo, Purchases, Favorites, etc in multiple views, create a Mixin that you can re-use.
class CommonUserInfoMixin (object):
def get_context_data(self, **kwargs):
context = super(OrgContextMixin, self).get_context_data(**kwargs)
... # Add more to context object
Then you can use this in your normal List, Detail, Update, etc CBV's
class ItemList(CommonUserInfoMixin, ListView):
....
When using Model class like this:
class MyModel(models.Model):
def __init__(self, *args, **kwargs):
self.myfield = models.Field()
super(MyModel, self).__init__(*args, **kwargs)
It doesn't take into consideration myfield(in the admin form, when saving the object... )
But if i declare like that:
class MyModel(models.Model):
myfield = models.Field()
It works just fine.
Why?
Edit
I think i have a good reason: I have an abstract class UploadItem that defines a field called file like this: self.file = models.FileField(upload_to=upload_to) As you can see, in each child class, i have to call parent init method with appropriate upload_to variable(say 'videos' for Video model). So i cannot do it the normal way.
Because the Django ORM code does some serious meta-magic during class definition (just browse the django/db code to see how magic). You are doing an end-run around that magic by creating fields on the fly in the __init__() function.
Is there a really good reason for not creating the class in the normal way? If not, then do it the normal way. If you do have a good reason then get ready to get into the really deep end of the pool -- both of Python and Django.
Setting a dynamic path for the upload_to attribute is absolutely not a good reason for wanting to muck around with model field declaration.
This is something that Django handles already - if you set upload_to to a callable, you can return the correct value dependent on the model instance. See the documentation.