I want to delete the data inside the file field and the file uploaded through the file field.
I'm beginner.
models.py
class Fruits(models.Model):
name = models.CharField(
_('Name'),
max_length=200,
)
description = models.TextField(
_('Description'),
null=True, blank=True,
)
this_is_my_file = models.FileField(
_('Photo image'),
null=True,
blank=True,
upload_to='myfile/'
)
def __str__(self):
return self.name
def delete(self, *args, **kwargs):
if self.this_is_my_file:
self.this_is_my_file.delete()
super().delete(*args, **kwargs)
Like the code above, I added 'def delete' to the existing model as shown above through search.
But I don't know how to use this function.
How do I use this in view and template?
My part of view is below.
views/fruits.py
class FruitsDetailView(LoginRequiredMixin, DetailView):
template_name = 'frutis/detail.html'
login_url = 'login'
model = MyObjects
def get_context_data(self, **kwargs):
pk = self.object.pk
context = super().get_context_data(**kwargs)
...
return context
How do I execute the delete function in this view?
I want to delete it when I press the 'delete' button on the template.
Should I send a post request from template and receive it from view?
I've been thinking about it for 4 days, but I don't know what to do.
Related
I have a home app with HomePage model which gets object from BlogPage model in blog app. I use this code below the obtain the object from BlogPage to HomePage.
blog app
class HomePage(Page):
primary_header = models.CharField(max_length=100, blank=True,)
secondary_header = models.CharField(max_length=100, blank=True,)
hero_banner_image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=False,
on_delete=models.SET_NULL,
related_name='+')
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
# Get object from Blog Page
blogpages = self.get_children().get(title='Blog Page').get_children().live().public().order_by('-first_published_at')
context['blogpages'] = blogpages
return context
I used get() to obtain the object by title, but I feel that it may not be the best way to do it. If I were to rename the BlogPage title field to for example, "The Blog Page", it will break the code since 'Blog Page' is no more used. Is there a better way to queryset from BlogPage to HomePage model?
home app
class BlogPage(Page):
subpage_types = ['PostPage']
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
category_slug = request.GET.get('category', None)
context['categories'] = BlogCategory.objects.all()
return context
If you know that your HomePage will only ever have one child of type BlogPage you can use the Wagtail PageQuerySet exact_type query.
blog_index_page = self.get_children().exact_type(BlogPage).first()
blog_pages = blog_index_page.get_children().live().public().order_by('-first_published_at')
Django queryset first - https://docs.djangoproject.com/en/3.0/ref/models/querysets/#first
type - https://docs.wagtail.io/en/stable/reference/pages/queryset_reference.html#wagtail.core.query.PageQuerySet.type
exact_type - https://docs.wagtail.io/en/stable/reference/pages/queryset_reference.html#wagtail.core.query.PageQuerySet.exact_type
If you are having trouble importing the model from another app, you can work around this with apps.get_model which is part of django.apps.
Note: You may need to do this import within your get_context to avoid circular import issues.
from django.apps import apps
MyModel1 = apps.get_model('app1', 'MyModel1')
https://docs.djangoproject.com/en/3.0/ref/applications/#django.apps.AppConfig.get_model
https://stackoverflow.com/a/43847288/8070948
I have a model Creator which is linked to the Django standard User model via a OneToOneField field. The Creator model is there to allow me more flexibility when adding/editing information of a Creator. Now for deleting a Creator I use the generic DeleteView. However, this does not delete the User instance and hence is not completely what I am looking to do (e.g. the username of the deleted Creator is "already taken"). Is there a way to use the default DeleteView to let a user delete his account? What is the best practice to do a "delete account" operation regarding deleting the User instance, logging out the user, and confirming the success of the operation?
What I tried so far:
models.py
class Creator(models.Model):
first_name = models.CharField(max_length=100, null=True, blank=True)
last_name = models.CharField(max_length=100, null=True, blank=True)
street_and_number = models.CharField(max_length=200, null=True, blank=True)
zip_code = models.CharField(max_length=30, null=True, blank=True)
location = models.CharField(max_length=100, null=True, blank=True)
state_province = models.CharField(max_length=100, null=True, blank=True)
country = models.CharField(max_length=100, null=True, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = slugify(self.user)
super(Creator, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('creator-detail', args=[str(self.slug)])
views.py
class CreatorDelete(LoginRequiredMixin, DeleteView):
#model = User # does not work
model = Creator
success_url = reverse_lazy('index')
# these two methods only give access to the users own profile but not the others
def user_passes_test(self, request):
if request.user.is_authenticated:
self.object = self.get_object()
return self.object.user == request.user
return False
def dispatch(self, request, *args, **kwargs):
if not self.user_passes_test(request):
return redirect_to_login(request.get_full_path())
return super(CreatorDelete, self).dispatch(request, *args, **kwargs)
urls.py
path('creator/<slug:slug>/delete/', views.CreatorDelete.as_view(), name='creator-delete')
Also this thread seemed quiet promising, but since I would like to use a user_confirm_delete.html template and rather a class based view (to implement a check that a user can only delete his own account) I didn't manage to make it work.
Override the delete() method as,
class CreatorDelete(LoginRequiredMixin, DeleteView):
.....
.....
.....
# your code
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.user.delete() # deleting the default "User" model
return HttpResponseRedirect(reverse('index'))
By default, Django admin page basically form submitted data set to database naturally without any data edits.
However, I want to edit this.
When I develop blog to use Django admin, I have columns in table like this
| title | article_md | article_html
and I want to make article_html data not to edit directly in django admin page form but to generate html style data from markdown style data of article_md and to submit to database.
How can I do this? Is there any way to do something like generally controller in model.py or admin.py?
class Article(models.Model):
def __str__(self):
return str(self.title)
title = models.CharField(max_length=255)
article_md = models.TextField(null=True)
article_html = models.TextField(null=True)←I want it is generated by converting article_md's data
model.py
class Article(models.Model):
def __str__(self):
return str(self.title)
title = models.CharField(
max_length=255
)
article_md = models.TextField(
null=True
)
article_html = models.TextField(
null=True
)
def save(self, *args, **kwargs):
self.article_html = markdown.markdown(self.article_md, extensions=['gfm'])
super(Article, self).save(*args, **kwargs)
admin.py
class ArticleAdmin(admin.ModelAdmin):
exclude = ['article_html']
admin.site.register(Article, ArticleAdmin)
I'm making a hobby project with Django to store my ideas seperated by idea groups as the following:
class Idea(models.Model):
name = models.CharField(unique=True, max_length=50)
description = models.TextField()
in_process = models.BooleanField()
is_done = models.BooleanField()
group = models.ForeignKey(Group, on_delete=models.CASCADE, blank=False)
class Group(models.Model):
name = models.CharField(unique=True, max_length=25)
description = models.CharField(max_length=50, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=False)
Is there any way to restrict the currently logged in user from being able to see or modify ideas and idea groups created by other users using generic class based views?
class GroupDelete(LoginRequiredMixin, generic.DeleteView):
model = Group
pk_url_kwarg = "id"
success_url = reverse_lazy('ideas:list')
...and a url for example:
urlpatterns = [
path('<int:id>/delete', views.GroupDelete.as_view(), name='delete'),
]
I'm using Django 2.0.
I would suggest writing a custom mixin where you'd inherit the LoginRequiredMixin and then add your own logic verifying that the currently logged in user (which you can retreive from request.user) is the one who actually created the Group object.
Simple example would look something like this:
# mixins.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseNotFound, HttpResponseRedirect
class YourCustomMixin(LoginRequiredMixin):
def dispatch(self, request, *args, **kwargs):
can_access = ... logic to check if user can access Group ...
disp = super().dispatch(request, *args, **kwargs)
if not isinstance(disp, HttpResponseRedirect) and not can_access:
return HttpResponseNotFound()
return disp
Once you have a value for the can_access flag, you call the LoginRequiredMixin's dispatch method and check if the result of that call is a redirect (to the login page) and check against the can_access flag, and then either return HttpResponseNotFound() or the original disp result.
Of course, you could also return HttpResponseForbidden() instead of HttpResponseNotFound().
You can then use it in your views, e.g.:
from your_app.mixins import YourCustomMixin
class GroupDelete(YourCustomMixin, generic.DeleteView):
...
Building a website with referring to a book, I made a blog application.
And I found even nonauthors can edit/delete the post which they didn't write. So I've tried to fix it in many ways but failed so far.
Here are my codes.
models.py
class Post(models.Model):
title = models.CharField('TITLE', max_length=50)
slug = models.SlugField('SLUG', unique=True, allow_unicode=True)
description = models.CharField('DESCRIPTION', max_length=100, blank=True)
content = models.TextField('CONTENT')
create_date = models.DateTimeField('Create Date', auto_now_add=True)
modify_date = models.DateTimeField('Modify Date', auto_now=True)
tag = TagField()
author = models.ForeignKey(User, null=True)
class Meta:
ordering = ('-modify_date',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail', args=(self.slug,))
def save(self, *args, **kwargs):
if not self.id:
self.slug = slugify(self.title, allow_unicode=True)
super(Post, self).save(*args, **kwargs)
views.py
class PostUpdateView(LoginRequiredMixin, edit.UpdateView):
model = Post
fields = ['title', 'slug', 'description', 'content', 'tag']
success_url = reverse_lazy('blog:index')
def form_valid(self, form):
form.instance.author = self.request.user
return super(PostUpdateView, self).form_valid(form)
class PostDeleteView(LoginRequiredMixin, edit.DeleteView):
model = Post
success_url = reverse_lazy('blog:index')
def form_valid(self, form):
form.instance.author = self.request.user
return super(PostDeleteView, self).form_valid(form)
Below is the only code which worked and I found it in docs(Using FormMixin with DetailView)
def post(self, request, *args, **kwargs):
if not ((request.user==Post.author) or request.user.is_superuser):
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
It worked, in some points, cuz it returns HttpResponseForbidden if nonauthor try to click "submit" in update form. However, what I want is that nonauthor cannot even access to update page.
I also found the way to customize dispatch() in stackoverflow but it didn't work.
I'm not sure whether it is proper in Django to use {% if not user == object.author %}{% else %}{% endif %} on templates like in PHP.
Any advice will be appreciated.
Thanks
The dispatch method is the right place to do this because it will affect all requests. As you've noticed, putting access control code in the post method doesn't affect GET requests.
How did you try to override dispatch? Because something like this should work:
from django.core.exceptions import PermissionDenied
class PostUpdateView(LoginRequiredMixin, edit.UpdateView):
#
# All of your other view code here....
#
def dispatch(self, request, *args, **kwargs):
handler = super().dispatch(request, *args, **kwargs)
user = request.user
post = self.get_object()
if not (post.author == user or user.is_superuser):
raise PermissionDenied
return handler
If you're supporting Python2 you'll have to change the super() call to super(PostUpdateView, self).dispatch(request, *args, **kwargs).