I recently got a problem that my django image field in my django app doesn't update the image after pressing "Post". In admin panel everything works fine. Maybe I missed something... Let me know.
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
categories = models.ManyToManyField('Category', related_name='posts')
image = models.ImageField(upload_to='images', default="images/None/no-img.jpg")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Category(models.Model):
name = models.CharField(max_length=20
)
views.py
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .models import Post
from django.contrib.auth.models import User
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
def home(request):
content = {
'posts': Post.objects.all()
}
return render(request, 'blog/home.html', content)
def blog_category(request, category):
posts = Post.objects.filter(categories__name__contains=category).order_by('-date_posted')
content = {
'category': category,
'posts': posts
}
return render(request, 'blog/blog_category.html', content) #<--(didn't add content block) bug found 05.11.19
def upload_pic(request):
if request.method == 'POST':
form = ImageUploadForm(request.POST, request.FILES)
if form.is_valid():
m = ExampleModel.objects.get(pk=course_id)
m.model_pic = form.cleaned_data['image']
m.save()
return HttpResponse('image upload success')
return HttpResponseForbidden('allowed only via POST')
...
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content', 'categories', 'image']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Post
fields = ['title', 'content', 'categories', 'image']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
I just have recently added Category and Image section in my web-application, the Category section works fine, but the image field just post default even if I'm selecting the current image. In the admin field it works well, so I decided to ask community about this annoying problem.
Make sure the form in your template has enctype set correctly:
Note that request.FILES will only contain data if the request method was POST and the that posted the request has the attribute enctype="multipart/form-data". Otherwise, request.FILES will be empty.
Related
please help me with one question, if possible.
I have a profile model that has a OneToOneField to User and there is a team field in the Profile model, there is also a Team model with a name, tag, etc. I would like to ask how to make the user who creates the team immediately be in it, so that the team field of the Profile model is assigned this team automatically, so that he is its creator and captain immediately. Maybe someone can help, explain, throw a banal example for understanding.
The creation was done like this, in a separate application. But I don't understand how to give the browser the created tim.
models.py
from django.db import models
from django.contrib.auth.models import User
from slugify import slugify
from django.urls import reverse
class BaseModel(models.Model):
objects = models.Manager()
class Meta:
abstract = True
class Profile(BaseModel):
user = models.OneToOneField(
User, on_delete=models.CASCADE, null=True, blank=True
)
nickname = models.CharField(max_length=30, unique=True, null=True)
team = models.ForeignKey('Team', on_delete=models.SET_NULL, blank=True, null=True)
def save(self, *args, **kwargs):
super(self.__class__, self).save(*args, **kwargs)
if self._state.adding is True:
Profile.objects.create()
def __str__(self):
return self.nickname
class Meta:
verbose_name = "Автор"
verbose_name_plural = "Авторы"
class Team(BaseModel):
name = models.CharField('Название', max_length=50)
tag = models.CharField('Тег', max_length=16, unique=True)
slug = models.SlugField(unique=True, blank=True, null=True)
def __str__(self):
return f'{self.name} [{self.tag}]'
def get_absolute_url(self):
return reverse("team_detail", kwargs={"slug": self.slug})
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Team, self).save(*args, **kwargs)
class Meta:
verbose_name = "Команда"
verbose_name_plural = "Команды"
forms.py
from django import forms
from django.contrib.auth.models import User
from django.forms import TextInput, Textarea, FileInput, IntegerField
from django.forms import TextInput, Textarea, FileInput, Select
from .models import *
class CreateTeamForm(forms.ModelForm):
class Meta:
model = Team
fields = {
'name', 'tag', 'slug'
}
views.py
from django.conf import settings
from django.contrib.auth import authenticate, login, get_user_model
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.shortcuts import render, redirect, resolve_url
from django.utils.http import url_has_allowed_host_and_scheme
from django.views.generic.base import View
from django.views.generic import DetailView, ListView
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.decorators.csrf import csrf_exempt
from .models import *
from .forms import *
# Create your views here.
class CreateTeam(View):
def get(self, request):
form = CreateTeamForm(request.POST)
context = {'form': form}
return render(request, 'team/home.html', context)
def post(self, request):
if request.method == 'POST':
form = CreateTeamForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
return redirect('home')
I'm just learning django, so it's hard to implement everything at once, and I'll be happy to help.
NEW CODE
forms.py
class JoinTeamForm(forms.ModelForm):
key = forms.CharField(label='key', max_length=20)
class Meta:
model = Team
fields = {'key'}
I tried without key = forms.CharField(label='key', max_length=20), but in html {{ form.key }} didn't work.
views.py
class JoinTeam(LoginRequiredMixin, View):
def get(self, request, pk):
print(f'post:{request.POST}, get:{request.GET}')
form = JoinTeamForm(request.POST or None)
team = Team.objects.get(id=pk)
context = {'form': form,
'team': team
}
return render(request, 'team/team_detail.html', context)
def post(self, request, pk):
print(f'post: {request.POST} team_id: {Team.objects.get(id=pk).key}')
profile = request.user.profile
error_msg = 'Неверный код'
if request.method == 'POST':
form = JoinTeamForm(request.POST)
role = Role.objects.get(id=2)
team = Team.objects.get(id=pk)
if form.is_valid():
key = form.save()
if key == team.key:
profile.team = team
profile.role = role
profile.save()
return redirect(team.get_absolute_url())
else:
return HttpResponse(error_msg)
return redirect(team.get_absolute_url())
Could you edit your view to update the user's profile after the team is created?
class CreateTeam(View):
def get(self, request):
form = CreateTeamForm(request.POST)
context = {'form': form}
return render(request, 'team/home.html', context)
def post(self, request):
profile = request.user.profile
if request.method == 'POST':
form = CreateTeamForm(request.POST)
if form.is_valid():
team = form.save()
profile.team = team
profile.save()
return redirect('home')
return redirect('home')
Please note, the way you have this set up is that each profile can only be on one team. If that's your intent, great, but if not you may want to set up a many to many model here so a user can be associated with multiple teams.
Main problem:
When user is at this url http://127.0.0.1:8000/8/, so group_id is already in url of his current page, he must choose group_id that he wants to assign task, if I do fields = ['title', completed'] in forms.py user can't choose group_id but he needs to. I have primary key but I don't know where to apply it in views
P.S.:
IndexView from views.py has no problem in it and works fine, also get method in GroupView works fine to. Anything works fine but user needs to choose a group that he want's to assign tasks
forms.py:
from django import forms
from .models import *
class AddTaskForm(forms.ModelForm):
class Meta:
model = Task
fields = '__all__'
class AddGroupForm(forms.ModelForm):
class Meta:
model = Group
fields = '__all__'
models.py
from django.db import models
from django.utils import timezone
class Group(models.Model):
title = models.CharField(max_length=255)
def __str__(self):
return self.title
class Task(models.Model):
title = models.CharField(max_length=255)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
completed = models.BooleanField(default=False)
def __str__(self):
return self.title
views.py
from django.shortcuts import render, redirect
from django.views import generic
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from .models import *
from .forms import *
class IndexView(generic.ListView):
template_name = 'tasks/index.html'
form_class = AddGroupForm
model = Group
def get_queryset(self):
return self.groups.order_by('title')
def get(self, request):
self.groups = Group.objects.all().order_by('title')
form = self.form_class(request.GET)
return render(request, self.template_name, {'form': form, 'groups': self.groups})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
return redirect('/')
return render(request, self.template_name, {'form': form, 'groups': self.groups})
class GroupView(generic.ListView):
template_name = 'tasks/group.html'
form_class = AddTaskForm
model = Task
def get_queryset(self):
return self.tasks.order_by('-completed', 'title')
def get(self, request, pk):
self.group_id = pk
self.tasks = Group.objects.get(pk=pk).task_set.all()
form = self.form_class(request.GET, pk)
return render(request, self.template_name, {'form': form, 'tasks': self.tasks})
def post(self, request, pk):
form = self.form_class(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.group_id = pk
form.save()
return HttpResponseRedirect(reverse('tasks:group', args=[pk]))
urls.py
from django.urls import path
from . import views
app_name = 'tasks'
urlpatterns = [
path('', views.IndexView.as_view(), name = 'index'),
path('<str:pk>/', views.GroupView.as_view(), name = 'group'),
]
Once you have the id in the url, you may use it in the form valid method. This is the place to add information befor writing to the DB:
def form_valid(self, form):
form.instance.group= Group.objects.get(pk=self.kwargs['pk'])
return super().form_valid(form)
By the way: Your url might be <int:pk> (not str) as automated generated pks are integer. And you may provide a better name for your parameter. Like <int:group_pk>
This makes your code more readable: self.kwargs['group_pk']
I am new to django, I migrated my models, the database is working fine, i can see the data that I added by the manage.py shell. But I cant add Data from my webApp. When I wrote text on the fields and press the submit button it gave me this error NOT NULL constraint failed: sms_post.author_id
Thanks for helping..
models.py files
from django.db import models
from django.contrib.auth.models import User
THE_GENDER = [
("Monsieur", "Monsieur"),
("Madame", "Madame")
]
class Post(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
gender = models.CharField(max_length=8, choices=THE_GENDER)
number = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
forms.py files
from django import forms
from .models import Post
from crispy_forms.helper import FormHelper
class post_form(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(post_form, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
class Meta:
model = Post
fields = ["name", "email", "gender", "number"]
views.py files
from django.shortcuts import render
from django.http import HttpResponse
from .forms import post_form
from django.contrib.auth.decorators import login_required
#login_required
def home(request):
form = post_form(request.POST or None)
if form.is_valid():
form.save()
context = {
"form": form
}
return render(request, "sms/home.html", context)
You did not set the author of the instance in your for to a User object. You can do this with:
from django.shortcuts import redirect
#login_required
def home(request):
if request.method == 'POST':
form = post_form(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect('name-of-view')
else:
form = post_form()
context = {
'form': form
}
return render(request, 'sms/home.html', context)
In order to implement the Post/Redirect/Get pattern [wiki], in case of a successful POST request, you should make a redirect, for example to the same view. You thus can here replace 'name-of-view' with the name of a view to redirect to.
Literaly like title say...check the picture. When i try to make new Post it says i made it but it wont show up on admin page nor in detail.html.
http://prntscr.com/n0pfrv
here is my code for post model
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(help_text="A short label, generally used in URLs.",default='', max_length=100)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['-date_posted']
def save(self):
slug = self.title
def get_absolute_url(self):
return reverse('detail', kwargs={'slug':self.slug})
def __str__(self):
return self.title
admin.py
from django.contrib import admin
from .models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ['title', 'slug', 'date_posted', 'author']
list_filter = ['title', 'date_posted']
prepopulated_fields = { 'slug': ('title',)}
admin.site.register(Post, PostAdmin)
views.py in app called blog were i have model Post also
from django.contrib import messages
from . models import Post
from django.core.mail import send_mail
from django.views.generic import DeleteView, ListView
def index_view(request):
return render(request, 'blog/index_view.html')
def blog_view(request):
context = {
'posts': Post.objects.all()
}
return render(request, 'blog/blog_view.html', context)
class PostDetailView(DeleteView):
model = Post
template_name = 'blog/detail.html'
context_object_name = 'post'
If you need any other of my code im gonna post it
You don't actually save the data in your save(self) method:
def save(self):
slug = self.title
super(Post, self).save(*args, **kwargs)
You should call the real save method as mentioned in the docs:
Overriding predefined model methods
models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=32)
class Article(models.Model):
author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True)
content = models.TextField()
forms.py
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['content']
In my web application, the author logs in and writes an article. So clearly, when the author is presented with an ArticleForm, he/she does not need to fill in the author field in the ArticleForm because the application already knows who the author is through the use of session variables.
This is the way I tried to add the author:
views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import Article
from .forms import ArticleForm
#login_required
def new_article(request):
author_name = request.session['author_name']
author = Author.objects.get(name=author_name)
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
form.save(commit=False)
form.author = author # I suspect the mistake is here
# I also tried form.author = author.id
form.save()
return redirect('success')
else:
form = ArticleForm()
return render(request, 'writings/new_article.html', {'form': form})
When I look at the database table, the author_id column is always NULL. What is wrong with my approach? How do I add a model relation before saving a ModelForm?
Capture the object returned from form.save(commit=False) and modify that rather than the form. EG:
if form.is_valid():
article = form.save(commit=False)
article.author = author
article.save()
return redirect('success')