I have articles that I manage via the admin section of Django.
My problem here is that I need to modify a field right after the administrator submited the form before it goes into database.
My specific need is to replace a part of a string with something else, but I don't know how to handle admin form submittions.
def save(self, *args, **kwargs):
self.title = 'someStuff' #Example
super().save(*args, **kwargs)
Here is the function to place under the model class. As simple as that
Related
i have two Django applications, blogApp and accounts, when i created a signal file for blogapp that can slugify title after saving the model into database, this works perfectly.
But when i added the second signal file to accounts that can create profile to the user when he finished his registration, it shows me this error:
, and when i check the admin section, i can see the profile has been successfully created.
PostModel in blogApp application:
Signals in blogApp application:
ProfileModel in accoounts application:
Signals in accounts application:
So, how can i create the user profile without indexing to Post signals.
Because what i'm thinking is the two signals of two apps is activating after the user press register.
I think, your problem is with the sender you have set.
You want to make a specific action about a Post instance,but you set User as sender ?
So in your receive function, you try to get a Post instance with as id the id of the user provided as isntance.
#receiver(post_save, sender=Post)
def slugify_title_model_field(sender, instance, created, **kwargs):
if created:
post_to_slugify = Post.objects.get(id=instance.id)
post_to_slugify.title = slugify(post_to_slugify.title)
post_to_slugify.slug = slugify(post_to_slugify.title)
post_to_slugify.save()
Of course, you have to remove the post_save.connect... write after this code.
But for this case, I advise you to overload the save function of your model, it is there for that, and it would be much more logical to put this function in a model because it directly concerns the instance being saved. I use signals to deal with cases external to the model itself in general.
class Post(models.Model):
...
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
I've seen a similar question, alas it has not been answered.
I have an app that features Entries (like blog entries) which include a part called SubEntry. I want the users to be able to report SubEntries (i.e. press the button 'report', fill some fields and the application sends an email to admins, saving the report in db is nice to have):
The flow should be like that: at the view EntryDetails (url: /entry/entry-title/) the user may click on the SubEntry part. The modal opens and the subentry is visualized in the modal as enlarged, with a button/link underneath 'Report the SubEntry'. Then it's possible to click on the 'Report the SubEntry' button and two fields appear - reason of reporting and contact detail of the reporter (here I am just toggling the visibility of the fields). I manage to display the form (with get overriden - overriding get_form_kwargs causes the error No Entry with that title) but either the Entry or its attributes are not displayed...
My questions are:
1) is creating a model for Reporting (ReportSubEntry) a decent approach?
2) I can't seem to pass the needed variable (an Entry object that is to be a ForeignKey for a SubEntry object that is being created) from CreateReport view to the report_subentry.html.
any thoughts, advice? Python 3.5, Django 1.10
models.py:
class ReportSubentry(models.Model):
Entry = models.ForeignKey('Entry')
details = models.CharField(max_length=100)
contact = models.EmailField()
forms.py:
class ReportEntryForm(forms.ModelForm):
class Meta:
model = ReportSubEntry
fields = ['details', 'contact', 'project']
views.py:
class CreateReport(CreateView):
model = ReportSubEntry
form_class = ReportSubEntryForm
template_name = 'understand/report_subentry.html'
# tried two methods to pass the variables:
def get(self, request, *args, **kwargs):
self.object = None
title = kwargs.get('title')
kwargs['entry'] = get_object_or_404(Entry, title=title)
return super(CreateReport, self).get(request, **kwargs)
def get_form_kwargs(self, **kwargs):
title = kwargs.get('title')
kwargs['entry'] = get_object_or_404(Entry, title=title)
return kwargs
The current model that you are using ReportSubEntry is perfect and there is no need to change it.
In your forms.py ReportEntryForm you have to use relatedfields to be able to correctly serialize the data. There is no need to override anything. When user clicks on report the sub entry you have to pass the pk of Entry model as it is required to know which entry is reported. I am assuming that since you are successfully displaying the entries pk of those are present. When you receive the pk with other two fields you get the corresponding entry for pk and then pass the object to ReportSubentry.objects.create method.
The reportentry form should not contain foreign key. You have two choices for that. First is remove that field and pass the pk of entry from frontend using ajax calls or use javascript to add a disabled input field which contains pk of entry when user clicks on report subentry.
Ok, so I've solved this issue.
The only solution that worked for me was overriding the get method of the ReportSubentry without calling the get method of the superclass:
def get(self, request, *args, **kwargs):
self.object = None
title = kwargs.get('title')
entry = get_object_or_404(Entry, title=title)
context_data = self.get_context_data()
context_data.update(entry=entry)
return self.render_to_response(context_data)
Please feel free to discuss it.
I am kind of new to Django, and i am trying to make sort of a news website where users can submit articles(with an account) but the admin needs to check them before they can be posted. Is that possible?
Yes, it is.
The simplest approach would be creating simple flag in model let's say a Boolean field named verified, which by default would be False. You could add permissions. So in the end you could overwrite a function in your admin form, and show the field for superuser only.
class MyUserAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
self.exclude = []
if not request.user.is_superuser:
self.exclude.append('Permissions') #here!
return super(MyUserAdmin, self).get_form(request, obj, **kwargs)
I want to prevent logged-in users to access login and register forms.
I've build custom mixin, but it isn't working. The problem is that even if the user is logged in, he can access login and register forms instead of beeing redirected to homepage.
My Mixin
class MustBeAnonymousMixin(object):
''' Only anonymous users (not logged in) may access login and register
'''
def dispath(self, *args, **kwargs):
if not self.request.user.is_anonymous:
return redirect(reverse('homepage'))
return super(MustBeAnonymousMixin, self).dispatch(*args, **kwargs)
LoginFormView
class LoginFormView(MustBeAnonymousMixin, TemplateView):
'''
Display basic user login form
'''
template_name = 'members/login.html'
def get_context_data(self, **kwargs):
context = super(LoginFormView, self).get_context_data(**kwargs)
context['login_form'] = UserLoginForm()
return context
I'm using Django 1.8. What am I doing wrong?
For another case where mixin does not work:
Remember: "Mixin param" must stand before "GenericView param"
Correct:
class PostDelete(LoginRequiredMixin, generic.DeleteView):
Incorrect:
class PostDelete(generic.DeleteView, LoginRequiredMixin):
Fix the typo in dispath and use is_authenticated() instead of is_anonymous (as indicated in the previous answer already)
is_anonymous should be a function call, and you probably should not use it:
is_anonymous()
Always returns False. This is a way of differentiating User and
AnonymousUser objects. Generally, you should prefer using is_authenticated() to this method.
One of the functionalities in a Django project I am writing is sending a newsletter. I have a model, Newsletter and a function, send_newsletter, which I have registered to listen to Newsletter's post_save signal. When the newsletter object is saved via the admin interface, send_newsletter checks if created is True, and if yes it actually sends the mail.
However, it doesn't make much sense to edit a newsletter that has already been sent, for the obvious reasons. Is there a way of making the Newsletter object read-only once it has been saved?
Edit:
I know I can override the save method of the object to raise an error or do nothin if the object existed. However, I don't see the point of doing that. As for the former, I don't know where to catch that error and how to communicate the user the fact that the object wasn't saved. As for the latter, giving the user false feedback (the admin interface saying that the save succeded) doesn't seem like a Good Thing.
What I really want is allow the user to use the Admin interface to write the newsletter and send it, and then browse the newsletters that have already been sent. I would like the admin interface to show the data for sent newsletters in an non-editable input box, without the "Save" button. Alternatively I would like the "Save" button to be inactive.
You can check if it is creation or update in the model's save method:
def save(self, *args, **kwargs):
if self.pk:
raise StandardError('Can\'t modify bla bla bla.')
super(Payment, self).save(*args, **kwargs)
Code above will raise an exception if you try to save an existing object. Objects not previously persisted don't have their primary keys set.
Suggested reading: The Zen of Admin in chapter 17 of the Django Book.
Summary: The admin is not designed for what you're trying to do :(
However, the 1.0 version of the book covers only Django 0.96, and good things have happened since.
In Django 1.0, the admin site is more customizable. Since I haven't customized admin myself, I'll have to guess based on the docs, but I'd say overriding the model form is your best bet.
use readonlyadmin in ur amdin.py.List all the fields which u want to make readonly.After creating the object u canot edit them then
use the link
http://www.djangosnippets.org/snippets/937/
copy the file and then import in ur admin.py and used it
What you can easily do, is making all fields readonly:
class MyModelAdmin(ModelAdmin):
form = ...
def get_readonly_fields(self, request, obj=None):
if obj:
return MyModelAdmin.form.Meta.fields
else: # This is an addition
return []
As for making the Save disappear, it would be much easier if
has_change_permission returning False wouldnt disable even displaying the form
the code snippet responsible for rendering the admin form controls (the admin_modify.submit_row templatetag), wouldnt use show_save=True unconditionally.
Anyways, one way of making that guy not to be rendered :
Create an alternate version of has_change_permission, with proper logic:
class NoSaveModelAdminMixin(object):
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
response = super(NoSaveModelAdmin, self).render_change_form(request, context, add, change,form_url, obj)
response.context_data["has_change_permission"] = self.has_real_change_permission(request, obj)
def has_real_change_permission(self, request, obj):
return obj==None
def change_view(self, request, object_id, extra_context=None):
obj = self.get_object(request, unquote(object_id))
if not self.has_real_change_permission(request, obj) and request.method == 'POST':
raise PermissionDenied
return super(NoSaveModelAdmin, self).change_view(request, object_id, extra_context=extra_context)
Override the submit_row templatetag similar to this:
#admin_modify.register.inclusion_tag('admin/submit_line.html', takes_context=True)
def submit_row(context):
...
'show_save': context['has_change_permission']
...
admin_modify.submit_row = submit_row