Django view redirect NoReverseMatch error - python

In Django project I have error NoReverseMatch after form save, redirecting to "parent view"
models.py
This is a models code - personnel
class Personnel(models.Model):
ID_Personnel = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
NameFirst = models.CharField(max_length=50)
NameLast = models.CharField(max_length=50)
IsActive = models.BooleanField(default=True, editable=True)
TimeCreation = models.DateTimeField(default=datetime.now, editable=False)
class IdentityDocument(models.Model):
ID_IdentityDocument = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
ID_Personnel = models.ForeignKey(Personnel, on_delete=models.PROTECT)
NumberSerial = models.CharField(max_length=50)
DateIssue = models.DateField(null=True)
DateExpiration = models.DateField(null=True)
NameIssuer = models.CharField(max_length=100, null=True)
IsActive = models.BooleanField(default=True, editable=True)
TimeCreation = models.DateTimeField(default=datetime.now, editable=False)
views.py - personnel
def personnel_edit(request, pk):
person = get_object_or_404(Personnel, ID_Personnel=pk)
if request.method == 'POST':
form = PersonnelForm(request.POST, instance=person)
if form.is_valid():
person = form.save(commit=False)
person.save()
return redirect('personnel_detail', pk=person.ID_Personnel)
else:
form = PersonnelForm(instance=person)
return render(request, 'personnel/personnel_edit.html', {'form': form})
def personnel_detail(request, pk):
person = get_object_or_404(Personnel, ID_Personnel=pk)
try:
document = IdentityDocument.objects.filter(ID_Personnel=pk).order_by('ID_IdType', '-DateExpiration').distinct(
'ID_IdType')
except IdentityDocument.DoesNotExist:
document = None
return render(request, 'personnel/personnel_detail.html',
{'person': person, 'document': document})
views.py - Setting ID_Personnel in Form
def identitydocument_new(request, fkey):
if request.method == 'POST':
form = IdentityDocumentForm(request.POST)
if form.is_valid():
iddoc = form.save(commit=False)
iddoc.ID_Personnel = Personnel.objects.get(ID_Personnel=fkey)
iddoc.save()
return redirect('personnel_detail', pk=fkey)
else:
form = IdentityDocumentForm()
return render(request, 'personnel/identitydocument_edit.html', {'form': form})
def identitydocument_edit(request, pk):
doc = get_object_or_404(IdentityDocument, ID_IdentityDocument=pk)
if request.method == 'POST':
form = IdentityDocumentForm(request.POST, instance=doc)
if form.is_valid():
doc = form.save(commit=False)
doc.save()
return redirect('personnel_detail', pk=doc.ID_Personnel)
else:
form = IdentityDocumentForm(instance=doc)
return render(request, 'personnel/identitydocument_edit.html', {'form': form})
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.personnel_list, name='personnel_list'),
path('personnel/<uuid:pk>/', views.personnel_detail, name='personnel_detail'),
path('personnel/new', views.personnel_new, name='personnel_new'),
path('personnel/<uuid:pk>/edit/', views.personnel_edit, name='personnel_edit'),
path('personnel/identitydoc/<uuid:fkey>/', views.identitydocument_new, name='identitydocument_new'),
path('personnel/identitydoc/<uuid:pk>/edit/', views.identitydocument_edit, name='identitydocument_edit'),
]
Form creates new documents and saveing it fine, but after editing it brings NoReverseMatch error.
Traceback

As that error shows, ID_Personnel is a reference to the entire related Personnel document. The URL needs the ID of that object. So you should do:
return redirect('personnel_detail', pk=doc.ID_Personnel_id)
But fundamentally this is a sign that your field name is incorrect. As I say, that is a reference to the object, not an ID, so it shouldn't have a name that implies it's an ID. Just call it Personnel. (Also, Python style is to use lower_case_with_underscore for attributes, so really it should be just personnel.)

Try this
from django.urls import reverse
redirect(reverse('personnel_detail', kwargs={'pk': doc.ID_Personnel}))

Related

how to prevent user from submitting the same form twice

I have the codes below in my views and models. But I want a situation in which a user cannot submit the same form twice. once a user submits the form he or she can only see a preview of what has been submitted but is unable to submit the same form.
Any help would be highly appreciated. Thanks
#views.py
def index(request):
form = MembershipForm()
if request.method == 'POST':
form = MembershipForm(request.POST)
if form.is_valid():
form.save()
return redirect("home")
return render(request, 'index.html', {'form': form)
#models.py
class Membership(models.Model):
fullname = models.CharField(max_length=500, blank=True, null=True)
location = models.IntegerField(default='0',blank=True, null=True)
department = models.IntegerField(default='0',blank=True, null=True)
last_update = models.DateTimeField(auto_now_add=False, auto_now=True)
def __str__(self):
return str(self.fullname)

Django form.save(commit=False) not adding user_id

I am trying to add created by whoever is logged in user but not getting that saved even though I am logged in. form.created_by = request.user is not adding logged in user.
def create_table_allotment(request):
form = TableAllotmentForm(request.POST or None)
context = {'form': form}
if request.method == 'POST':
if form.is_valid():
try:
form.save(commit=False)
form.created_by = request.user
form.save()
return redirect('order_management:table_allotment_home')
except IntegrityError as err:
print('err => ', err)
context['unique_error'] = 'User has already assigned table for today'
return render(request, 'orders/table_allotment/create.html', context)
Here are my models
class QOTs(models.Model):
name = models.CharField(max_length=50)
alias = models.CharField(max_length=10)
def __str__(self):
return str(self.name)
class Meta:
verbose_name_plural = "QOTs"
class TableAllotment(models.Model):
employee = models.ForeignKey(User, on_delete=models.PROTECT)
qot = models.ForeignKey(QOTs, on_delete=models.PROTECT)
club = models.CharField(max_length=20, default='POS-0001')
from_table = models.IntegerField()
to_table = models.IntegerField()
working_date = models.DateField(default=timezone.now)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='qot_creator')
created_at = models.DateTimeField(_("Created at"), auto_now_add=True, editable=False)
updated_at = models.DateTimeField(_("Updated at"), auto_now=True)
class Meta:
ordering = ('-id',)
unique_together = ('employee', 'working_date',)
Here is my form
class TableAllotmentForm(forms.ModelForm):
class Meta:
model = models.TableAllotment
fields = ["employee", "qot", "from_table", "to_table"]
Please help
form.save(commit=False) will return the instance wrapped by the form which you can then modify and call save on. Instead you are just calling save on the form again and also you are setting form.created_by = request.user i.e. you are setting an attribute on the form.
Instead you should directly modify the instance wrapped by the form:
def create_table_allotment(request):
form = TableAllotmentForm(request.POST or None)
context = {'form': form}
if request.method == 'POST':
if form.is_valid():
try:
form.instance.created_by = request.user
form.save()
return redirect('order_management:table_allotment_home')
except IntegrityError as err:
print('err => ', err)
context['unique_error'] = 'User has already assigned table for today'
return render(request, 'orders/table_allotment/create.html', context)
Note: TableAllotmentForm(request.POST or None) is an anti-pattern (It is possible for an empty form to be valid in certain conditions) and you should simply pass request.POST only if
request.method == "POST" else you should simply write
TableAllotmentForm().
An alternative approach to what Abdul Aziz Barkat has suggested would be to assign returned object of save()(Django-Docs) method like so obj = form.save(commit=False).
I would also add #login_required to the view
from django.contrib.auth.decorators import login_required
#login_required
def create_table_allotment(request):
if request.method == 'POST':
form = TableAllotmentForm(request.POST)
if form.is_valid():
try:
obj = form.save(commit=False)
obj.created_by = request.user
obj.save()
return redirect('order_management:table_allotment_home')
except IntegrityError as err:
print('err => ', err)
context['unique_error'] = 'User has already assigned table for today'
else:
form = TableAllotmentForm()
context = {'form': form}
return render(request, 'orders/table_allotment/create.html', context)

Django duplicates my entry when I store something

When I try to save a post, the post is saved, but current user is not registered and the post is duplicated with a blank entry and the current user is not stored.
For adding the post I use not the admin app but a personal template and form.
See the problem:
This is my view code:
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import NewAdminPostForm
from .models import Post, Category
# Create your views here.
def home(request):
posts = Post.objects.all()
categories = Category.objects.all()
posts_last = Post.objects.order_by('-created_at')[0:3]
return render(request, 'front/blog-list.html', {'posts': posts,
'categories': categories, 'posts_last': posts_last})
#login_required
def newadminpost(request):
if request.method == 'POST':
form = NewAdminPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
Post.objects.create(
message=form.cleaned_data.get('message'),
category_id=post.category_id,
created_by=request.user
)
#post.save()
return redirect('listadminpost')
else:
form = NewAdminPostForm()
return render(request, 'back/new-post-blog.html', {'form': form})
#login_required
def listadminpost(request):
posts = Post.objects.all()
return render(request, 'back/list-post-blog.html', {'posts': posts})
Form of my Blog:
from django import forms
from .models import Post, Category
class NewAdminPostForm(forms.ModelForm):
title = forms.CharField(label="Titre de l'article", max_length=255,)
message = forms.CharField(widget=forms.Textarea(),
max_length=4000,
help_text="Contenu de l'article")
pre_message = forms.CharField(label="Message de prévisu",
widget=forms.Textarea(),
max_length=4000,
help_text="Contenu de l'article")
class Meta:
model = Post
fields = ['title','meta_desc','message','pre_message','category']
Model of my Blog:
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
description = models.TextField(max_length=1000)
def __str__(self):
return self.name
def get_categories_count(self):
return Category.objects.filter(post__category=self).count()
class Post(models.Model):
title = models.CharField(max_length=255)
meta_desc = models.TextField(max_length=320, null=True)
pre_message = models.TextField(max_length=4000, null=True)
message = models.TextField(max_length=4000)
category = models.ForeignKey(Category, on_delete='cascade')
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE,
blank=True, null=True)
def __str__(self):
return self.title
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.create
your code:
post.save()...Post.objects.create(
from the link above:
A convenience method for creating an object and saving it all in one step. Thus:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
are equivalent.
So what you do in your code:
you save post object created from form
you create and save another Post instance by calling create method
choose any of them, just one, and this will avoid duplicates.
Instead of doing this:
#login_required
def newadminpost(request):
if request.method == 'POST':
form = NewAdminPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
Post.objects.create(
message=form.cleaned_data.get('message'),
category_id=post.category_id,
created_by=request.user
)
#post.save()
return redirect('listadminpost')
else:
form = NewAdminPostForm()
return render(request, 'back/new-post-blog.html', {'form': form})
You could do this: cleaner, easier to read, more up-to-date, and easier to maintain:
class AdminCreateView(LoginRequiredMixin, generic.CreateView):
model = Request
form_class = RequestForm
def form_valid(self, form):
result = super(AdminCreateView, self).form_valid(form)
title = form.cleaned_data.get('title')
meta_desc = form.cleaned_data.get('meta_desc')
message = form.cleaned_data.get('message')
# and so on. if there's something you refuse (ex title empty) do this:
if not title:
form.add_error('title', _("Precise the title"))
return self.form_invalid(form)
Post.objects.create(message=message,
meta_desc=meta_desc,
title=title,) # and so on
return result

Django how to change forms or views.py?

i create simple page where i can add article (title, text and category). When i do it on 'site administration everything is ok', but when i add it on page i can't choose category.
http://i.stack.imgur.com/4Nxzb.jpg
I choose category, for example like on this screen but my article do not have this category after i save it (article is uncategorized).
I created forms.py file and i done it like this:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text', 'categories')
How must i change 'categories' here to make it usable?
models.py:
from django.db import models
from django.utils import timezone
class Category(models.Model):
name = models.CharField('Nazwa Kategorii', max_length=100)
slug = models.SlugField('Odnośnik', max_length=100)
icon = models.ImageField('Ikonka Kategorii', upload_to='icons',
blank=True)
class Meta:
verbose_name = "Kategoria"
verbose_name_plural = "Kategorie"
def __unicode__(self):
return self.name
class Post(models.Model):
author = models.CharField(max_length=25, blank=True, null=True)
title = models.CharField(max_length=200)
slug = models.SlugField('Odnośnik', max_length=255)
text = models.TextField()
published_date = models.DateTimeField(
default=timezone.now)
categories = models.ManyToManyField(Category, verbose_name='Kategorie')
def publish(self):
self.published_date = timezone.now()
self.save()
def __unicode__(self):
return self.title
And from views.py my view
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('blog.views.post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
When you save a form using commit=False you should call the save_m2m() method of the form:
post = form.save(commit=False)
post.author = request.user
post.save()
form.save_m2m()
Another, more elegant, solution is to pass the instance with preset field to the form's constructor. Is this case you don't need to use the commit=False argument:
form = PostForm(request.POST, instance=Post(author=request.user))
if form.is_valid():
post = form.save()
return redirect('blog.views.post_detail', pk=post.pk)

Django Forms Updating Record Issues

I am getting an error when I try to update a record in Django using a form. I get an error that a record with that number already exists. Below is my model and view. This is really driving me nuts. I though that Django would just update the record instead of trying to write a new record.
class Report(models.Model):
report_number = models.CharField(max_length=4, unique=True)
detected = models.CharField(max_length=40)
computer_name = models.CharField(max_length=40)
username = models.CharField(max_length=15)
cab_date_time = models.CharField(max_length=40)
collector = models.CharField(max_length=40)
addresses = models.TextField()
fault = models.CharField(max_length=40)
known_malware = models.TextField(default='No')
collected_files = models.TextField(default='None')
registry_keys = models.TextField()
service_number = models.CharField(max_length=15, blank=True)
notes = models.TextField(blank=True)
sample_requested = models.CharField(max_length=4, blank=True)
action = models.CharField(max_length=35, blank=True)
And View
def reports(request, report_number):
instance = get_object_or_404(Report, report_number=report_number)
form = ReportForm(request.POST or None, instance=instance)
if form.is_valid():
form.save()
return HttpResponseRedirect('/')
return render(request, 'reports/report.html', {'form': form})
Here is the Form defination
from django.forms import ModelForm
from reports.models import Report
class ReportForm(ModelForm):
class Meta:
model = Report
exclude = ('moderator',)
def reports(request, report_number):
instance = get_object_or_404(Report, report_number=report_number)
if request.method == 'POST':
form = ReportForm(request.POST, instance=instance)
if form.is_valid():
form.save(force_update=True)
return HttpResponseRedirect('/')
else:
form = ReportForm(instance=instance)
return render(request, 'reports/report.html', {'form': form})

Categories

Resources