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')
Related
This is my models.py file
from django.db import models
# Create your models here.
class Blog(models.Model):
name = models.CharField(max_length=120)
created_on = models.DateTimeField(auto_now_add=True)
class Article(models.Model):
blog = models.ForeignKey(Blog,
on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=120)
body = models.TextField()
draft = models.BooleanField(default=False)
This is my forms.py file
from blog.models import Article
from django import forms
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'body', 'draft']
Here is the views.py file
from django.shortcuts import render
from django.http import HttpResponse
from blog.forms import ArticleForm
# Create your views here.
def add_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse("Article created")
else:
context = {'form': ArticleForm()}
return render(request, 'add_article.html', context)
context = {'form': ArticleForm()}
return render(request, 'add_article.html', context)
Can someone tell me how do I insert the first attribute of class Article which is blog in class Articleform?
I am learning django and some help will be appreciated.
You can check these steps:
be sure you added {{form}} in your add_article.html.
be sure you added method="POST" in your <form> tag.
e.g.:
<form method="POST">
{{form}}
<input type="submit">Post</input>
</form>
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.
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.
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.
I'm using a ModelForm in Django but some fields are not saved to the database...
models.py file
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.forms import ModelForm
# Create your models here.
class Bill(models.Model):
image_name = models.CharField(max_length=150)
upload_date = models.DateTimeField(default=timezone.now)
image = models.ImageField()
description = models.TextField(blank=True)
result = models.CharField(max_length=1000)
uploaded_by = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return str(self.result + self.description)
forms.py file
from django import forms
from django.db import models
from django.forms import ModelForm
from .models import Bill
class BillForm(ModelForm):
class Meta:
model = Bill
fields = ['image', 'description']
exclude = ['result', 'image_name', 'upload_date', 'uploaded_by']
views.py file
def upload(request):
if request.method == 'POST':
form = BillForm(request.POST, request.FILES)
if form.is_valid():
form.image_name = request.FILES['image']
form.upload_date = datetime.now()
form.uploaded_by = request.user
form.result = "something"
form.save()
return redirect('cism-home')
else:
form = BillForm()
return render(request, 'auth/upload.html', {'form': form})
So the image and description fields are saved but other fields are not. Any ideas why is that?
Your form is excluding some fields, so you can't "access" those fields using:
form.upload_date (for example), because they don't exists.
What you can do is:
if form.is_valid():
bill = form.save(commit=False)
bill.image_name = request.FILES['image']
bill.upload_date = datetime.now()
bill.uploaded_by = request.user
bill.result = "something"
bill.save()
If you want a quick description about what "commit=False" do, you can check:
Django ModelForm: What is save(commit=False) used for?