When i try to upload an image in the admin panel of django, i get this Forbidden (CSRF token missing.): /ckeditorupload/ i have this result in my console.
here my model
from django.db import models
from django.contrib.auth.models import User
from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField
# Create your models here.
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
#content = RichTextField(blank=True, null=True)
image = RichTextUploadingField()
#image = models.ImageField(upload_to='featured_image/%Y/%m/%d/') #
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
my views
from django.views import generic
from .models import Post
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
#method_decorator(csrf_exempt, name='dispatch')
class PostList(generic.ListView):
queryset = Post.objects.filter(status=1).order_by('-created_on')
template_name = 'index.html'
class PostDetail(generic.DetailView):
model = Post
template_name = 'post_detail.html'
I tried to exempt the CSRF but i get same issues, & when i delete the middlewareCsrf it's dont works too, since i'm using the admin django and not a custom post method, i dont know where to pass the {{ csrf_token }}
Thanks for your help :)
I had a similar problem some time ago, it was as if all of a sudden there was no csrf_token available anymore in the user session. After a bit of tinkering this solved it.
import:
from django.middleware.csrf import get_token
in the view:
csrf_token = get_token(request)
context = {
"csrf_token": csrf_token,
}
In the template I still use {% csrf_token %}, but I also make some API calls in JavaScript and in those ones I instead used directly the token that i passed through the context -> {{ csrf_token }}
Related
I am new to Django & DRF and I am trying to replace the default api view given from ModelViewSet (scr1,scr2,scr3) with custom HTML templates. Default view works just fine, i've tested with postman and it can do CRUD functions(at least it seems so), but I have no idea how to substitute the default views with custom html pages. I did follow DRF docs - it worked, also searcged solutions(this one was promising), but I simply can't adopt it my situation. Please help!
models.py:
from django.db import models
class Package(models.Model):
prod_name = models.CharField(max_length=255, default=0)
quantity = models.IntegerField(default=0)
unit_price = models.IntegerField(default=0)
def __str__(self):
return self.prod_name
class Orders(models.Model):
order_id = models.CharField(max_length=255, default=0)
package = models.ManyToManyField(Package)
is_cod = models.BooleanField(default=False)
def __str__(self):
return self.order_id
serializers.py:
from rest_framework import serializers
from .models import Package, Orders
class PackageSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.IntegerField()
prod_name = serializers.CharField(max_length=255, default=0)
quantity = serializers.IntegerField(default=0)
unit_price = serializers.IntegerField(default=0)
class Meta:
model = Package
fields = "__all__"
class OrderSerializer(serializers.HyperlinkedModelSerializer):
package = PackageSerializer(many=True)
def get_or_create_packages(self, packages):
print("this is package in gocp:", packages)
package_ids = []
i = 0
for package in packages:
print("i=", i)
i += 1
package_instance, created = Package.objects.get_or_create(pk=package.get('id'), defaults=package)
print("package id:", package.get('id'))
package_ids.append(package_instance.pk)
print("package_ids:", package_ids)
return package_ids
def create_or_update_packages(self, packages):
package_ids = []
for package in packages:
package_instance, created = Package.objects.update_or_create(pk=package.get('id'), defaults=package)
package_ids.append(package_instance.pk)
return package_ids
def create(self, validated_data):
print("this is validated_data:", validated_data)
package = validated_data.pop('package', [])
print("this is package:", package)
order = Orders.objects.create(**validated_data)
order.package.set(self.get_or_create_packages(package))
return order
def update(self, instance, validated_data):
package = validated_data.pop('package', [])
instance.package.set(self.create_or_update_packages(package))
fields = ['order_id', 'is_cod']
for field in fields:
try:
setattr(instance, field, validated_data[field])
except KeyError: # validated_data may not contain all fields during HTTP PATCH
pass
instance.save()
return instance
class Meta:
model = Orders
fields = "__all__"
views.py:
from .serializers import OrderSerializer, PackageSerializer
from .models import Package, Orders
from rest_framework import viewsets
class OrderViewSet(viewsets.ModelViewSet):
serializer_class = OrderSerializer
queryset = Orders.objects.all()
class PackageViewSet(viewsets.ModelViewSet):
serializer_class = PackageSerializer
queryset = Package.objects.all()
urls.py:
from django.urls import path, include
router = DefaultRouter()
router.register(r'order', OrderViewSet, basename='orders')
router.register(r'package', PackageViewSet, basename='package')
urlpatterns = [
path('api/', include(router.urls)),
]
I am assuming that:
list(), create()/update() needs to be modified in views.py (class OrderViewSet & PackageViewSet), but how? I did try many different options to define - list(), create()/update() functions, but nothing worked, for example(in this particular case im not allowed to overide existing list method):
#action (renderer_classes=[TemplateHTMLRenderer], detail=True)
def list(self, request, *args, **kwargs):
template_name = 'order_list.html'
queryset = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data, template_name='order_list.html')
Actual html templates need to conform to the nested model that I have and I am not sure how it would work with nested data. Since I can't solve the 1st point, can't test out and try to solve the 2nd point.
Will rendering_form serializer work? Taking the DRF docx exaple from work?:
{% load rest_framework %}
<html><body>
<h1>Orders - {{ orders.order_id }}</h1>
<form action="{% url 'order-detail' pk=orders.pk %}" method="POST">
{% csrf_token %}
{% render_form serializer %}
<input type="submit" value="Save">
</form>
</body></html>
Perhaps I should forget ModelsViewSet and go with APIView?(though in this particular case if there exist a solution I would prefer to know it).
I have a model.py file that has classes Author and Article. Article has a foreign key referencing Author. I have created a view,blogCreate, using a form ,ArticleForm, in my forms.py file. Since author in class Article is a foreign key, it means that author will be chosen from the Author queryset. This means that the select tag will automatically used by the form, instead I want to use the <input type="text" > tag so that I can create an instance of Author using the input and not select from the queryset.
forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'content', 'aurthor')
widgets = {
'title': forms.TextInput(attrs={
'class': 'title'}),
'content': forms.Textarea(attrs={
'class': 'text_input',
'name': 'article_content'}),
# Changed to TextInput so it can use <input type="text" >
'aurthor': forms.TextInput(attrs={
'class': 'text_input',
'name': 'aurthor_name'})
}
models.py
from django.db import models
from ckeditor.fields import RichTextField
class Aurthor(models.Model):
name = models.CharField("Author Name", max_length=100)
def __str__(self):
return self.name
class Article(models.Model):
title = models.CharField("Title", max_length=100)
content = RichTextField(blank=True, null=True)
pub_date = models.DateTimeField("Publish Date", auto_now_add = True)
aurthor = models.ForeignKey(Aurthor, on_delete=models.CASCADE)
def __str__(self):
return self.title
views.py
from .models import Article, Aurthor
from django.views.generic import CreateView
from .forms import ArticleForm
class blogCreate(CreateView):
model = Article
form_class = ArticleForm
template_name = 'BlogHandler/blog.html'
blog.html
<form action="" method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Post</button>
</form>
I finally found a way to do exactly what I wanted, I don't if how efficient it is but it works. Let me know if there is a better way.
forms.py
from django import forms
from .models import Article, Author
class ArticleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
self.fields['author'] = forms.CharField(max_length=100, required=True)# author is required
class Meta:
model = Article
fields = ('title', 'content', )
In the question, I stated that I'd changed the widget for author to TextInput so that I could enter text not an instance of Author.This didn't work out the way I wanted, so instead I removed author from fields and made a custom field author that is not a field in my model. This way I still get the text input to create my Author instance.
models.py
class Article(models.Model):
title = models.CharField("Title", max_length=100, null=False)
content = RichTextField(blank=True, null=False)
pub_date = models.DateTimeField("Publish Date", auto_now_add = True)
author = models.ForeignKey(Author, on_delete=models.CASCADE, null=True)
I made author nullable in my models.py file but it is okay because I made the custom auhtor field in forms.py required so that all Articles made using the site have an Author. I was getting some error before this change
views.py
class articleCreate(CreateView):
model = Article
form_class = ArticleForm
def form_valid(self, form):
rt = super().form_valid(form)
article = form.save(commit=False)
author_name = self.request.POST['author'].title()
author, created = Author.objects.get_or_create(name=author_name)
article.author = author
article.save()
return rt
Here I first pause the save so that I can create an Author using the text input from the custom field author, which is simple text, if the Author instance already exists it gets else it creates it. Then I save and I'm done.
I am the newbie of writing programming, now I am learning django.
I have a problem for URL redirection. I create the model and it does work at admin site.
Also I set the PK for each article, that successfully generate the URL by PK.
However when I post the message form the front-end, after posting it appear the error message suppose it should be redirect to the page of DetailViewand
I have imported the reverse function in my model, but it seem not working.
My python version : 3.7.6 and django version : 3.0.0
ImproperlyConfigured at /add/
No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.
My View
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView
from .models import Page
class PageListView(ListView):
model = Page
template_name='home.html'
context_object_name = 'all_post_list'
class PageDetailView(DetailView):
model = Page
template_name='post.html'
class PageCreateView(CreateView):
model = Page
template_name='post_new.html'
fields = ['title', 'author', 'body', 'body2']
Model
from django.urls import reverse
from django.db import models
from ckeditor.fields import RichTextField
class Page(models.Model):
title = models.CharField(max_length=50)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = RichTextField()
body2 = models.TextField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post', args=[str(self.id)])
URL
from django.urls import path
from .views import PageListView, PageDetailView, PageCreateView
urlpatterns = [
path('add/', PageCreateView.as_view(), name='post_new'),
path('', PageListView.as_view(), name='home'),
path('blog/<int:pk>/', PageDetailView.as_view(), name='post'),
]
Thanks for helping. :)
I think your indentation is the problem here. Fix it by:
class Page(models.Model):
title = models.CharField(max_length=50)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = RichTextField()
body2 = models.TextField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post', args=[self.id])
I have the below models for which I'm trying to create a form for:
class Letter(models.Model):
title = models.CharField(max_length=100)
publish_date = models.TimeField()
class LetterRecipients(models.Model):
letter = models.ForeignKey(Letter)
recipient_name = models.CharField(max_length=200)
recipient_rating = models.IntegerField()
has_responded = models.BooleanField()
I'd like a single form that allows the user to enter a title and publish_date for the letter, and in the same form enter multiple recipients by name and rating.
Can anyone help with creating the form model for this? I can't figure out how to have django generate this form using {{ form.as_p }}. I think I'll have to use jQuery to create the additional recipient rows on the HTML page, but how would I get django to parse those into the model?
Any help would be greatly appreciated.
Thanks.
Ark
Ark, you can use ModelMultipleChoiceField in Django form. Here are some roughly example. I create "posts" apps just for quick testing :
forms.py
from django import forms
from django_test.posts.models import Letter, LetterRecipients
class LetterForm(forms.Form):
title = forms.CharField()
publish_date = forms.TimeField()
recepient = forms.ModelMultipleChoiceField(
queryset=LetterRecipients.objects.all()
)
models.py
from django.db import models
class Letter(models.Model):
title = models.CharField(max_length=100)
publish_date = models.TimeField()
class LetterRecipients(models.Model):
letter = models.ForeignKey(Letter)
recipient_name = models.CharField(max_length=200)
recipient_rating = models.IntegerField()
has_responded = models.BooleanField()
def __unicode__(self):
return self.recipient_name
views.py
# Create your views here.
from django_test.posts.forms import LetterForm
from django.shortcuts import render
def index(request):
form = LetterForm()
data = {'form': form}
return render(request, 'posts/index.html', data)
index.html
{% load url from future %}
{{ form.as_p }}
I am trying to create a delete function for my Workout model.
This is the model:
class Workout(models.Model):
workoutID = models.AutoField(primary_key=True)
name = models.CharField(max_length=40)
created_by = models.ForeignKey(User)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def delete(self):
return reverse("delete_workout", kwargs = {'workout_id': self.workoutID})
Next I have the view:
def delete_workout(request, workout_id):
workout = get_object_or_404(Workout, workoutID = workout_id)
print(workout)
if request.user != workout.created_by:
return HttpResponse('Not ur workout')
else:
workout.delete()
return HttpResponseRedirect('/')
This is the url:
url(r'^(?P<workout_id>\d+)/delete/$', views.delete_workout, name='delete_workout'),
And finally the html:
<a href='{{ instance.delete }}'>
<button>Delete Workout</button>
</a>
I'm not getting any errors in the console, which is why I don't know what is going wrong.
You are overriding delete method of the class just for getting the delete url. You will get the url by url function in the template like {% url delete_workout instance.workoutID %}. So remove the delete function from the model change your html href url. Leave the view and url as the same. No issues there
class should be
class Workout(models.Model):
workoutID = models.AutoField(primary_key=True)
name = models.CharField(max_length=40)
created_by = models.ForeignKey(User)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
And your html should be
<a href='{% url delete_workout instance.workoutID %}'>
<button>Delete Workout</button>
</a>
NOTE: django model itself adds id for each table, so you dont have to specify it as you did workoutID = models.AutoField(primary_key=True).
By default each model will have a id field just like id = models.AutoField(primary_key=True)
If you consider removing the workoutID then the model becomes
class Workout(models.Model):
name = models.CharField(max_length=40)
created_by = models.ForeignKey(User)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
and the html will be
<a href='{% url delete_workout instance.id %}'>
<button>Delete Workout</button>
</a>
Django has all the tools for you under the hood. Don't reinvent the wheel. You can refactor and simplify your code.
First remove the method delete in Workout.
Second, replace your function-based-view with a class-based-view:
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
from django.http import Http404
from .models import Workout
class WorkoutDeleteView(DeleteView):
model = Workout
success_url = reverse_lazy('delete_workout')
def get_object(self):
obj = super().get_object()
if obj.created_by != self.request.user:
raise Http404
return obj
A workout can be deleted only by its author. In success_url you specify the target where the user should be redirected after deleting.
Just adapt slightly your urls.py (pay attention to the emphasised part):
url(r'^(?P<pk>\d+)/delete/$', views.WorkoutDeleteView.as_view(), name='delete_workout'),
EDIT:
You can name your views as you please, however it would be better to follow already well established conventions. Thus the names for the class based views should be workout-list, workout-detail, workout-create, workout-update and workout-delete.