I created a model and respective ModelForm, view and Template for it, but ModelForm does not save data to the model even though .save() function is used.
I have tried reviewing forms and views but I do not know what is wrong.I have posted the respective models, forms, views and templates in the question.
models.py:
class Centre(models.Model):
Location = (
('rashmi_heights', 'Rashmi Heights Centre'),
('Levana', 'Levana Centre')
)
name= models.CharField(max_length=50, blank=False, choices=Location, unique=True)
address = models.CharField(max_length =250)
contact = models.CharField(max_length=100, blank=False)
phone = PhoneField(blank=True, help_text='Contact phone number')
def __str__(self):
return self.name
forms.py:
class CentreForm(forms.ModelForm):
class Meta():
model = Centre
fields = '__all__'
views.py:
def centre(request):
forms = CentreForm()
if request.method == 'POST':
forms = CentreForm(request.POST)
if forms.is_valid():
centre = forms.save(request.POST)
centre.save()
else:
forms = CentreForm()
return render(request,'NewApp/centreinfo.html',{'forms':forms})
template:
<!DOCTYPE html>
{% extends 'NewApp/base.html' %}
{% load staticfiles %}
{% block body_block %}
<div class="jumbotron">
<h2>Fill details about your centre.</h2><br>
<h3> </h3>
<form method="post" enctype="multipart/form-data">
{{forms.as_p}}
{% csrf_token %}
<a class="btn btn-primary" href="{% url 'NewApp:centreinfo' %}">Submit</a>
</form>
</div>
{% endblock %}
forms.py:
class CentreForm(forms.ModelForm):
class Meta: -> change here
model = Centre
fields = '__all__'
def centre(request):
forms = CentreForm()
if request.method == 'POST':
forms = CentreForm(request.POST)
if forms.is_valid():
forms.save(request.POST)
else:
forms = CentreForm()
return render(request,'NewApp/centreinfo.html',{'forms':forms})
html
<form method="post" enctype="multipart/form-data">
{{forms.as_p}}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Related
I'd like to make a POST REQUEST with an existing HTML FORM, to store it in a database, but everytime I tried to submit data through the form, it gives me the following error
By the way I'm doing this following those post:
Django form using HTML template
MultiValueDictKeyError generated in Django after POST request on login page
Registro.html
{% extends "RegistrarProyecto/layout.html" %}
{% block title %} {% endblock %}
{% block content %}
<h1>Crear Usuario</h1>
<form class="CrearUsuario" action="{% url 'registro' %}" method="POST">
{% csrf_token %}
<input type="text",name="NombreProyecto", placeholder="Nombre del Proyecto" >
<br>
<br>
<input type ="text", name="ResponsableProyecto", placeholder ="Responsable del proyecto">
<br>
<br>
<textarea name="DescripcionProyecto", rows="4", cols="50"></textarea>
<br>
<br>
<input type="submit" value="Registrar">
</form>
<br>
Ir a Bienvenido
{% endblock %}
views.py
def registro(request):
if request.method == 'POST':
NombreProyecto = request.POST.get('NombreProyecto')
ResponsableProyecto = request.POST.get('ResponsableProyecto')
DescripcionProyecto = request.POST.get('DescripcionProyecto')
Proyecto.objects.create(NombreProyecto=NombreProyecto,ResponsableProyecto=ResponsableProyecto,DescripcionProyecto=DescripcionProyecto)
return redirect("RegistrarProyecto/index.html")
return render(request, 'RegistrarProyecto/Registro.html')
models.py
from django.db import models
# Create your models here.
class Proyecto(models.Model):
NombreProyecto = models.CharField(max_length = 64)
ResponsableProyecto = models.CharField(max_length= 64)
DescripcionProyecto = models.CharField(max_length = 64)
def __str__(self):
return f"{self.NombreProyecto}"
class Evaluador(models.Model):
NombreEvaluador = models.CharField(max_length=64)
Proyecto = models.ManyToManyField(Proyecto, blank=True, related_name="Evaluador")
def __str__(self):
return f"{self.NombreEvaluador} {self.Proyecto}"
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("Registro", views.registro, name="registro")
]
it is this line:
<input type="text",name="NombreProyecto", placeholder="Nombre del Proyecto" >
change it to:
<input type="text", name="NombreProyecto", placeholder="Nombre del Proyecto" >
I'd suggest two things. 1. Either you set your model field as null-able that even it doesn't get a value for one of those fields it will still be saved. For example:
class Proyecto(models.Model):
NombreProyecto = models.CharField(max_length=64, null=True, blank=True)
ResponsableProyecto = models.CharField(max_length=64, null=True, blank=True)
DescripcionProyecto = models.CharField(max_length=64, null=True, blank=True)
def __str__(self):
return f"{self.NombreProyecto}"
Set your html input and textarea fields with the required attribute required. That values are passed for all fields.
I'm trying to get a list of objects in Django from a model.
I just want to get the list of 'dht node' from the request user, but it shows nothing in the html file (as if the list was empty). The user that I'm using has 2 'dht nodes' and they're shown in the django admin.
I don't know what is wrong, because if I use the instruction "member.dht.create(...)" in the views function and a create a new 'dht node' like this, this is shown. Only 'dht nodes' that I enter by form do not show. Can be the form?
Thanks a lot, Here's my code:
Models.py
class Node(models.Model):
name = models.CharField(primary_key=True, null=False, max_length= 50)
description= models.CharField(default=None, null=False, max_length= 250)
topic=models.CharField(default=None, null=False, max_length= 50, unique=True)
def __unicode__(self):
return self.name
class dht(Node):
temp = models.IntegerField(default=None, null=True)
hum = models.IntegerField(default=None, null=True)
class UserProfile(User):
uid = models.CharField(default=None, null=False, max_length= 250)
dht = models.ManyToManyField(dht, blank=True)
def __unicode__(self):
return self.user.username
Views.py -dht list-
#login_required(login_url = '/web/login')
def listDhtSensor(request):
member = request.user.userprofile
list = member.dht.all()
return render(request, 'web/listDhtSensor.html', {'list':list})
Html -listDhtSensor.html-
{% block content %}
{% for dht in list %}
{{ dht.name }}
{{ dht.topic }}
{% endfor %}
{% endblock %}
Forms.py
class newDHTSensorForm(forms.ModelForm):
class Meta:
model = dht
field = ['name',
'description',
'topic',]
labels = {'name': 'Name' ,
'description': 'Description',
'topic': 'Topic',}
exclude = ['temp', 'hum']
Views.py -dht form-
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Html -newDhtSensor.html-
{% block content %}
<div class="boxReg">
<form method="post">
{% csrf_token %}
<h2>{{ form.name.errors.as_text }}</h2>
<p><label for="id_name">Name:</label> <input class="barraForm" type="text" name="name" maxlength="150" autofocus="" required="" id="id_name"></p>
<p><label for="id_description">Description:</label> <input class="barraForm" type="text" name="description" maxlength="150" id="id_description"></p>
<h2>{{ form.topic.errors.as_text }}</h2>
<p><label for="id_topic">Topic:</label> <input class="barraForm" type="text" name="topic" maxlength="254" id="id_topic"></p>
<div class="boxButtonReg">
<button class="buttonReg" type="submit">Save</button>
</div>
</form>
</div>
{% endblock %}
It shows nothing because you did not link you dht objects to that UserProfile, so if you later query for the dhts for that UserProfile, evidently the list is empty. You should add it to the dht relation, like:
#login_required(login_url = '/web/login')
def newDHTSensor(request):
if request.method == "POST":
form = newDHTSensorForm(request.POST)
if form.is_valid():
post = form.save()
request.user.userprofile.dht.add(post)
return redirect('/web/dhtDetail')
else:
form = newDHTSensorForm()
return render(request, 'web/newDhtSensor.html', {'form': form})
Note that you first need to save the post, so you should omit the commit=False aprameter.
I've created a new form for comments the articles on a website. When I add the new comment from django admin everything works ok, but when I try to add the new comment directly from detail page nothings happen and I'am redirecting to the page with list of articles.
here are my files
models.py:
class Komentarz(models.Model):
post = models.ForeignKey(Wpisy, related_name="komentarze", verbose_name="Komentarze do artykułu", on_delete=models.CASCADE)
name = models.CharField(max_length=80, verbose_name="Imię")
email = models.EmailField(verbose_name="Email")
content = models.TextField(verbose_name="Treść komentarza")
created_date = models.DateTimeField(verbose_name="Utworzono", auto_now_add=True)
active = models.BooleanField(verbose_name="Aktywny?", default=True)
class Meta:
ordering = ('created_date',)
verbose_name="Komentarz"
verbose_name_plural="Komentarze"
def __str__(self):
return 'Komentarz dodany przez {} dla strony {}'.format(self.name, self.post)
vies.py with the function of details
from django.shortcuts import render, get_object_or_404
from .models import Wpisy, Komentarz
from .forms import KomentarzeForma
....
def detale_bajki(request, slug, ):
detale_bajki = get_object_or_404(Wpisy, slug=slug)
komentarze = detale_bajki.komentarze.filter(active=True)
if request.method == 'POST':
formularz_komentarza = KomentarzeForma(data=request.POST)
if formularz_komentarza.is_valid():
nowy_komentarz = formularz_komentarza.save(commit=False)
nowy_komentarz.detale_bajki = detale_bajki
nowy_komentarz.save()
else:
formularz_komentarza = KomentarzeForma()
return render(request, 'bajki/detale_bajki.html', {'detale_bajki': detale_bajki, 'komentarze': komentarze, 'formularz_komentarza': formularz_komentarza})
forms.py
from .models import Komentarz
from django import forms
class KomentarzeForma(forms.ModelForm):
class Meta:
model = Komentarz
fields = ('name', 'email', 'content')
and detail.html
...
{% with komentarze.count as total_komentarze %}
<h2>
{{ total_komentarze }} komentarz{{ total_komentarze|pluralize:"y" }}
</h2>
{% endwith %}
{% for komentarz in komentarze %}
Komentarz dodany przez <strong>{{komentarz.name}}</strong>
{{komentarz.created_date}}
<p>
{{ komentarz.content|linebreaks }}<br>
{% empty %}
<p>Nie dodano jeszcze żadnych komentarzy</p>
{% endfor %}
{% if nowy_komentarz %}
<h2>Twój komentarz został dodany</h2>
{% else %}
<h2>Dodaj nowy komentarz</h2>
<form action="." method="post">
{{formularz_komentarza.as_p}}
{% csrf_token %}
<p><input type="submit" value="Dodaj komentarz"></p>
</form>
{% endif %}
clas Wpisy in models.py
class Wpisy(models.Model):
title = models.CharField(max_length=400, verbose_name="Tytuł")
slug = models.SlugField(unique=True, max_length=400,verbose_name="Przyjazny adres url")
content = models.TextField()
status_audio = models.BooleanField(default=False, verbose_name="Czy dostępny będzie plik audio?")
audio_file = models.FileField(upload_to='uploads/',verbose_name="Plik audio")
created_date = models.DateTimeField(blank=True, null=True, verbose_name="Data utworzenia")
category = models.ForeignKey(Kategorie, verbose_name="Kategoria", on_delete=models.CASCADE)
class Meta:
verbose_name="Wpis"
verbose_name_plural="Wpisy"
def __str__(self):
return self.title
Your url pattern is
path('bajki/<slug>', views.detale_bajki, name='detale_bajki')
Note that it doesn't have a trailing slash. Your form's action is "."
<form action="." method="post">
That means you are submitting to /bajki/, which is the wrong URL.
You could fix this by adding a trailing slash to the url (which is common in Django URLs)
path('bajki/<slug>/', views.detale_bajki, name='detale_bajki')
Or you could change the form action to "" instead of ".". In the comments it looks like you fixed the issue by changing the form action to {{ detale_bajki.slug }}.
However these changes to the form action are fragile, and could break if you change your URL patterns again. The best approach is to use the {% url %} tag to reverse the correct URL.
<form action="{% url 'detale_bajki' detale_bajki.slug %}" method="post">
Try out:
nowy_komentarz.post = detale_bajki
...
return render(request, 'html page', {'key': 'what you want to return to your context'}) # don't fornget to add some return to your view.
I'm working on a school project. Right now any user can ask a question.
In order to notify all the users when any users asks a question I've created a new app & notifying them through the simple 'view' whenever a question is asked. But it's just plain notifications yet.
How can I mark them read once a user opens the Notification tab? Just like on social networks!
I suggest you to use ContentType to make a dynamic notifications fo any models. This snippet below is an example how to implement the notification system;
1. in your models.py
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from django.utils.translation import ugettext_lazy as _
class ContentTypeToGetModel(object):
"""
requires fields:
- content_type: FK(ContentType)
- object_id: PositiveIntegerField()
"""
def get_related_object(self):
"""
return the related object of content_type.
eg: <Question: Holisticly grow synergistic best practices>
"""
# This should return an error: MultipleObjectsReturned
# return self.content_type.get_object_for_this_type()
# So, i handle it with this one:
model_class = self.content_type.model_class()
return model_class.objects.get(id=self.object_id)
#property
def _model_name(self):
"""
return lowercase of model name.
eg: `question`, `answer`
"""
return self.get_related_object()._meta.model_name
class Notification(models.Model, ContentTypeToGetModel):
# sender = models.ForeignKey(
# User, related_name='notification_sender')
receiver = models.ForeignKey(
User, related_name='notification_receiver')
content_type = models.ForeignKey(
ContentType, related_name='notifications', on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(_('Object id'))
content_object = GenericForeignKey('content_type', 'object_id')
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
STATUS_CHOICES = (
('reply', _('a reply')),
('comment', _('a comment')),
('message', _('a message'))
)
status = models.CharField(
_('Status'), max_length=20,
choices=STATUS_CHOICES, default='comment')
is_read = models.BooleanField(
_('Is read?'), default=False)
def __str__(self):
title = _('%(receiver)s have a %(status)s in the %(model)s:%(id)s')
return title % {'receiver': self.receiver.username, 'status': self.status,
'model': self._model_name, 'id': self.object_id}
class Meta:
verbose_name_plural = _('notifications')
ordering = ['-created']
2. in your views.py
from django.views.generic import (ListView, DetailView)
from yourapp.models import Notification
class NotificationListView(ListView):
model = Notification
context_object_name = 'notifications'
paginate_by = 10
template_name = 'yourapp/notifications.html'
def get_queryset(self):
notifications = self.model.objects.filter(receiver=self.request.user)
# mark as reads if `user` is visit on this page.
notifications.update(is_read=True)
return notifications
3. in your yourapp/notifications.html
{% extends "base.html" %}
{% for notif in notifications %}
{{ notif }}
{# for specific is like below #}
{# `specific_model_name` eg: `comment`, `message`, `post` #}
{% if notif._model_name == 'specific_model_name' %}
{# do_stuff #}
{% endif %}
{% endfor %}
So, when I creat that notifications?
eg: when the other user send a comment to receiver on this post.
from django.contrib.contenttypes.models import ContentType
def send_a_comment(request):
if request.method == 'POST':
form = SendCommentForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
#instance.sender = request.user
...
instance.save()
receiver = User.objects.filter(email=instance.email).first()
content_type = ContentType.objects.get(model='comment')
notif = Notification.objects.create(
receiver=receiver,
#sender=request.user,
content_type=content_type,
object_id=instance.id,
status='comment'
)
notif.save()
How about menu? Like this stackoverflow, facebook, instagram, or else?
you can handle it with templatetags, eg:
# yourapp/templatetags/notification_tags.py
from django import template
from yourapp.models import Notification
register = template.Library()
#register.filter
def has_unread_notif(user):
notifications = Notification.objects.filter(receiver=user, is_read=False)
if notifications.exists():
return True
return False
and the navs.html menu:
{% load notification_tags %}
{% if request.user.is_authenticated %}
<ul class="authenticated-menu">
<li>
<a href="/notifications/">
{% if request.user|has_unread_notif %}
<i class="globe red active icon"></i>
{% else %}
<i class="globe icon"></i>
{% endif %}
</a>
</li>
</ul>
{% endif %}
First you need ManyToManyField for user module who is readed a post.
profile.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
subscribed = models.ManyToManyField(User, related_name='subscribed', blank=True)
readed = models.ManyToManyField("blogs.BlogPost", related_name='readed', blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.user.username)
class Meta:
ordering = ("-created",)
If you have a blog model like this:
class BlogPost(models.Model):
author = models.ForeignKey(Profile, on_delete=models.CASCADE)
post_title = models.CharField("Post Title", max_length=150, unique=True)
post_content = models.TextField("Content")
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.post_title
class Meta:
ordering = ("-created",)
You need to create a button function in blog posts view.
def mark_as_read_button(request):
if request.method == "POST":
my_profile = Profile.objects.get(user=request.user)
post = request.POST.get("post_pk")
obj = BlogPost.objects.get(pk=post)
if obj in my_profile.readed.all():
my_profile.readed.remove(obj)
else:
my_profile.readed.add(obj)
return redirect(request.META.get("HTTP_REFERER"))
return redirect("blogs:subscribed-blogs")
Then you can use is in the template file like this:
{% extends 'base.html' %}
{% block title %}Subscribed Blog Posts{% endblock %}
{% block content %}
{% for post in posts %}
<h5 class="card-title">{{ post.post_title }}</h5>
{% if post in readed %}
<form action="{% url "blogs:mark_as_read" %}" method="POST">
{% csrf_token %}
<input type="hidden" name="post_pk" value={{ post.pk }}>
<button type="submit" class="btn btn-danger btn-sm">Mark as unread</button>
</form>
{% else %}
<form action="{% url "blogs:mark_as_read" %}" method="POST">
{% csrf_token %}
<input type="hidden" name="post_pk" value={{ post.pk }}>
<button type="submit" class="btn btn-success btn-sm">Mark as read</button>
</form>
{% endif %}
<p class="card-text">{{ post.created }}</p>
<p class="card-body">{{ post.post_content }}</p>
<hr>
{% endfor %}
{% endblock %}
Good coding.
I created two classes: Client (attributes: name and sex) and Account (attributes: customer[fk], the payment status). I show the form from templates; When I click the link "Add Customer" it opens the form of creation, from what has in models.py, other words can only create a client to "name and sex," but not I can integrate in the same form payment situation.
models.py
from django.db import models
class Cliente(models.Model):
SEXO = (
('M', 'Masculino'),
('F','Feminino'),
)
nome = models.CharField("Nome do cliente", max_length=255)
sexo = models.CharField("Sexo", max_length=1, choices=SEXO)
def __unicode__(self):
return self.nome
class Meta:
verbose_name = 'Cliente'
verbose_name_plural = 'Clientes'
class Conta(models.Model):
STATUS_CONTA = (
('A', 'A Pagar'),
('P', 'Pago'),
)
cliente = models.ForeignKey(Cliente, related_name='conta')
situacao = models.CharField("Situação", max_length=50, choices=STATUS_CONTA)
class Meta:
verbose_name = 'Conta'
verbose_name_plural = 'Contas'
def __unicode__(self):
return self.cliente.nome
forms.py
from django.forms.models import ModelForm
from cadastro.models import Cliente, Conta
__author__ = 'Admin'
class ClienteForm(ModelForm):
class Meta:
model = Cliente
index.html
<html>
<body>
<a href='/adicionar_cliente/'>Adicionar cliente</a>
{% for cliente in clientes %}
{% for conta in cliente.conta.all %}
<p>Nome: {{cliente.nome}}</p>
<p>Sexo: {{cliente.get_sexo_display}} </p>
<p>Situação do pedido: {{conta.get_situacao_display}}</p>
{% endfor %}
<p><a href='/excluir/{{cliente.id}}/'>Excluir?</a></p>
<p><a href='/editar/{{cliente.id}}/'>Editar</a></p>
<hr>
{% empty %}
<h3>Não existe nenhum cliente.</h3>
{% endfor %}
</body>
</html>
form.html
<html>
<body>
<form action='/{{action}}/' method='post'>
{% csrf_token %}
<table>
{{form}}
</table>
<input type='submit' value='Adicionar' />
</form>
</body>
</html>
You can create two forms to accomplish this task.
forms.py
...
class ClienteForm(ModelForm):
class Meta:
model = Cliente
class ContaForm(ModelForm):
class Meta:
model = Conta
exclude = ("cliente") #exclude the cliente field from showing up in the form rendering.
form.html
<html>
<body>
<form action='/{{ action }}/' method='post'>
{% csrf_token %}
<table>
{{ form.as_table }} <!-- added as table which was missing from original post. -->
{{ form2.as_table }}
</table>
<input type='submit' value='Adicionar' />
</form>
</body>
views.py
...
def form(request):
if request.method == 'POST':
form = ClienteForm(request.POST)
form2 = ContaForm(request.POST)
if form.is_valid() and form2.is_valid():
client = form.save()
conta = form2.save(commit=False)
conta.cliente = client
contra.save()
else:
form = ClienteForm()
form2 = ContaForm()
return render_to_response('form.html', locals(), context_instance = RequestContext(request))