I am facing issues in saving data to my sqlite db using Django.
When i am accessing 127.0.0.1/personal/makeentry--> the page shows the form , but when i click on submit after entering the details, the detils are not saved in db.
Below is the code
model.py
from django.db import models
class Account(models.Model):
accountId = models.IntegerField(primary_key=True,unique=True,
blank=False, null=False, auto_created=True)
accountName = models.CharField(max_length=100)
countryName = models.CharField(max_length=100)
marketName = models.CharField(max_length=100)
msdmName = models.CharField(max_length=100)
deliveryManagedFrom = models.CharField(max_length=100)
location = models.CharField(max_length=100)
def __str__(self):
return self.accountName
admin.py
from django.contrib import admin
from .models import Account
# Register your models here.
class AccountAdmin(admin.ModelAdmin):
list_display = ['accountId', 'accountName','countryName', 'marketName',
'msdmName','deliveryManagedFrom','location']
admin.site.register(Account, AccountAdmin)
forms.py
from django import forms
from . models import Account
from django.forms import ModelForm
class AccountForm(forms.Form):
accountName = forms.CharField(label="Account Name", max_length=100)
countryName = forms.CharField(label="Country Name", max_length=100)
marketName = forms.CharField(label="Market Name", max_length=100)
msdmName = forms.CharField(label="MSDM Name", max_length=100)
deliveryManagedFrom = forms.CharField(label="Delivery Managed From", max_length=100)
location = forms.CharField(label="Location", max_length=100)
class AccountForm(ModelForm):
class Meta:
model = Account
fields = ['accountName','countryName', 'marketName', 'msdmName', 'deliveryManagedFrom', 'location']
views.py
from django.shortcuts import render
from django.views import generic
from .models import Account
from .forms import AccountForm
def index(request):
return render(request, 'personal/home.html')
# generic view to fetch the data then show in a list
class IndexView(generic.ListView):
# a name to refer to the object_list(to be used in the index.html)
context_object_name = 'account_list'
template_name = 'personal/index.html'
def get_queryset(self):
return Account.objects.all()
# generic view to show the details of a particular object
class DetailsView(generic.DetailView):
model = Account
template_name = 'personal/detail.html'
def makeentry(request):
if request.method == 'POST':
form = AccountForm(request.POST)
if form.is_valid():
accountName = request.POST.get('Account Name', '')
countryName = request.POST.get('Country Name', '')
marketName = request.POST.get('Market Name', '')
msdmName = request.POST.get('MSDM Name', '')
deliveryManagedFrom = request.POST.get('Delivery Managed From', '')
location = request.POST.get('Location', '')
account = Account(accountName=accountName, countryName=countryName, marketName=marketName, msdmName=msdmName, deliveryManagedFrom=deliveryManagedFrom, location=location)
account.save()
form = AccountForm()
return render(request, 'personal/makeentry.html', {'form': form})
else:
form = AccountForm()
return render(request, 'personal/makeentry.html', {'form': form})
makeentry.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Account Entry</title>
</head>
<body>
<form action="{% url 'makeentry' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
</body>
</html>
detail.html
{% if account_list %}
<table>
<tr>
<td> Account Name </td>
<td> Country Name </td>
<td> Market Name </td>
<td> MSDM Name </td>
<td> Delivery Managed From </td>
<td> Location </td>
</tr>
{% for account in account_list %}
<tr>
<td>{{ account.accountName }}</td>
<td>{{ account.countryName }}</td>
<td>{{ account.marketName }}</td>
<td>{{ account.msdmName }}</td>
<td>{{ account.deliveryManagedFrom }}</td>
<td>{{ account.location }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
I think you are making this harder than it needs to. You have a Form and a ModelForm of the same name. You should just be able to use the ModelForm. If there are attributes you want to pass with your ModelForm check out ModelForm Overriding default widgets. It has also been my experience to set action=“” and let the view handle the redirect on success.
def make_entry(request):
if request.POST:
form = AccountForm(request.POST)
if form.is_valid():
new_form = form.save()
return redirect('where-you-want-to-redirect ',
# View current saved info or change to what you want to show
pk=new_form.pk)
Related
I have previously figured out how to send and save notifications by many to many fields to send to users, now i can't specifically call the notifications by current user logged in i.d.
Models.py
class Notifications(models.Model):
id=models.AutoField(primary_key=True)
sent_to = models.ManyToManyField(CustomUser)
message = models.TextField(null=True)
message_reply = models.TextField(null=True)
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
The notifications_sent_to is the created table after I created the many to many save
Notifications_sent_to table (which is not created in the models)
Notifications table (which stores the message)
Views.py
def add_notification(request):
notifs = Notifications.objects.all()
users = CustomUser.objects.filter(is_staff=True)
if request.method == 'POST':
form = AddNotifForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.message_reply = "none"
instance.save()
form.save_m2m()
sent_to = form.cleaned_data.get('sent_to')
messages.success(request, f'Message has been successfully sent .')
return redirect('add_notif')
else:
form = AddNotifForm()
context={
'notifs' : notifs,
'form' : form,
'users' : users,
}
template_name ='main-admin/add-notif.html'
return render(request, template_name, context)
Forms.py
class AddNotifForm(forms.ModelForm):
sent_to = forms.ModelMultipleChoiceField(
queryset=CustomUser.objects.filter(is_staff=True).exclude(is_superuser=True),
widget=forms.CheckboxSelectMultiple,
required=True)
class Meta:
model = Notifications
fields = ['sent_to', 'message']
Templates view
{% for sent_to_users in sent_to_users %}
<tr>
<td>{{ sent_to_users.id }}</td>
<td>{{ sent_to_users.sent_to }}</td>
<td>{{ sent_to_users.message }}</td>
<td>
{% if sent_to_users.message_reply == "none" %}
<button type="button" class="btn btn-primary reply_open_modal" data-bs-toggle="modal" data-bs-target="#replyModal">Reply</button>
{% else %}
{{ sent_to_users.message_reply }}
{% endif %}
</td>
<td>{{ sent_to_users.created_at }}</td>
</tr>
{% endfor %}
Every time an user adds a new post, country name in user's info get repeated.
For example. Someone from USA adds post, name USA repeated many times.
I tried to use distinct 'country = Post.objects.all().distinct('country')' then I get this error
'DISTINCT ON fields is not supported by this database backend'.
my views.py
def countries(request):
country = Post.objects.all().distinct('country')
context = {
'posts': country
}
return render(request, 'users/countries.html', context)
my models.py
from PIL import Image
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.db.models.signals import post_save
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
first_name = models.CharField(verbose_name="First name", max_length=255)
last_name = models.CharField(verbose_name="First name", max_length=255)
country = models.CharField(verbose_name="Country name", max_length=255)
city = models.CharField(verbose_name="City name", max_length=255)
email = models.EmailField(verbose_name="Email", max_length=255)
def __str__(self):
return self.username
class Post(models.Model):
title = models.CharField(max_length=255)
country = models.CharField(max_length=255)
city = models.CharField(max_length=255)
address = models.CharField(max_length=255)
email = models.EmailField(max_length=255)
phone = models.CharField(max_length=255)
website = models.URLField(max_length=255)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('users:blog')
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = Profile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
my urls.py
from django.urls import path
from .views import UserRegistrationView, CabinetView, PostCreateView, PostUpdateView, PostDetailView, PostDeleteView
from . import views
app_name = 'users'
urlpatterns = [
path('accounts/register/', UserRegistrationView.as_view(), name='register'),
path('accounts/cabinet/', CabinetView.as_view(), name='cabinet'),
path('accounts/cabinet/blog/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('accounts/cabinet/new/', PostCreateView.as_view(), name='post-create'),
path('accounts/cabinet/blog/<int:pk>/update/', PostUpdateView.as_view(), name='post-update'),
path('accounts/cabinet/blog/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'),
path('', views.home, name='home'),
path('accounts/cabinet/blog/', views.blog, name='blog'),
path('accounts/cabinet/countries/', views.countries, name='countries'),
path('accounts/cabinet/cities/<int:pk>', views.cities, name='cities'),
]
my countries.html
{% extends 'shared/base.html' %}
{% load staticfiles %}
{% block content %}
<div class="content-section p-5 mt-5 pl-4">
<table class="table table-hover text-left col-sm-6" style="table-layout: fixed; word-wrap: break-word;">
<tbody>
<tr>
<th>No: </th>
<th>Countries: </th>
</tr>
</tbody>
</table>
{% for post in posts %}
<table class="table table-hover text-left col-sm-6" style="table-layout: fixed; word-wrap: break-word;">
<tbody>
<tr>
<td>{{ post.id }}</td>
<td>{{ post.country }}</td>
</tr>
</tbody>
</table>
{% endfor %}
{% endblock %}
</div>
If you need only the list of countries, why don't use .values()? I think following code should do the job, if you want only the list of countries?
countries = Post.objects.values("country").distinct()
And the result will be a queryset with dict-like objects, i.e.:
[{"country": "USA"}, {"country": "Canada"}, ...]
I guess You are using SQLite Database. .distinct() can't be used with sqlite3 so you will have to switch to something like postgresql to use it or modify your query.
so if you can't change your database then just manually filter your database. but think switching to another database would be the best solution to this problem
I'm creating a website for general education uses and one of the features is a calendar section where I would like the user to be able to store their events but then when they login they can view the events they created. This is for an academic assignment.
I can't seem to get this calendar to link to a user field. I would like each record in the calendar table to have a user_id which will be the same as the current_user. I understand that you can user the django default user auth but i have not done that due to not knowing about it and by the time I realized it was too late.
So all I really need to do is when the form is valid, I need to assign the value of the current_user id as the value for student in the calendar table. But for some reason I keep getting problems and the form isn't detected as being valid or the program just doesn't assign the value.
My main objective is to have each user view their own calendar. I don't mind changing the current student field to a foreign key field
Student.Views
def calendar(request):
student_obj = Student.objects.get(student_name=current_user)
print(student_obj)
if request.method == 'POST':
form = EventsForm(initial={'student': '3'} or request.POST)
print(form.errors)
if form.is_valid():
form.save()
all_events = Events.objects.filter(student=student_obj.id)
messages.success(request, 'Event Has Been Added')
return render(request, 'Student/calendar.html', {'all_events': all_events})
else:
messages.success(request, 'Event Has NOT Been Added')
all_events = Events.objects.filter(student=student_obj.id)
return render(request, 'Student/calendar.html', {'all_events': all_events})
Student.Models
class Student(models.Model):
student_name = models.CharField(max_length=59, default=None)
username = models.CharField(max_length=59)
password = models.CharField(max_length=59)
age = models.PositiveIntegerField()
date_of_birth = models.DateField(max_length=10)
form = models.CharField(max_length=3)
email = models.EmailField(max_length=59)
present = models.PositiveIntegerField(default=0)
late = models.PositiveIntegerField(default=0)
absent = models.PositiveIntegerField(default=0)
maths_grade = models.PositiveIntegerField(default=0)
english_grade = models.PositiveIntegerField(default=0)
science_grade = models.PositiveIntegerField(default=0)
behaviour_level = models.PositiveIntegerField(default=0)
def __str__(self):
return self.student_name
class Events(models.Model):
student = models.CharField(max_length=200)
date = models.DateField(max_length=10, default=None)
event = models.CharField(max_length=200)
completed = models.BooleanField(default=False)
Student.forms
class EventsForm(forms.ModelForm):
class Meta:
model = Events
fields = ["event", "completed", "date", "student"]
Calendar Template
<div class="container" style="color: #fff">
<br/>
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible" roles="alert">
<button class="close" data-dismiss="alert">
<small>x</small>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% if all_events %}
<div>
<table class="table table-dark table-bordered">
{% for things in all_events %}
{% if things.completed %}
<style>
.striker {
text-decoration: line-through;
text-color: black;
}
</style>
<tr class="table-danger striker">
<td style="color: black">{{ things.date }}</td>
<td>{{ things.event }}</td>
<td><center>Delete</center></td>
</tr>
{% else %}
<tr>
<td>{{ things.date }}</td>
<td >{{ things.event }}</td>
<td><center>Delete</center></td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
{% endif %}
Change form.save() to
event = form.save(commit=False)
event.student = request.user
event.save()
That'll do it.
Don't make it complicated, this have to be easier. If I understood what are you trying to do I would create my models as following:
#model.py
from django.db.models.signals import post_save
from django.dispatch import receiver
class Student(models.Model):
user= models.OneToOneField(User, null=True) #student is user
#Define student fields...
class Calendar(models.Model):
#Defile calender fields here along with its default values ...
user = models.OneToOneField(Student)
'''
this signal populate calender table with user_id along with its
calender fields
'''
#receiver(post_save, sender=Student)
def create_student_calender(sender, instance, created, **kwargs):
if created and not kwargs.get('raw', False):
calendar = Calender(user=instance)
calendar.save()
class Event(models.Model):
calender = models.ForeignKey(Callender, null=True)
# Define event fields here ...
With models structure like this, whenever student create account Calendar model will be populated saved with calendar fields and student's id field.
So how do student create their events? Simply create an a inlineformset_factory form to create events on each student's calendar like this:
#form.py
from django.forms import inlineformset_factory
from django import forms
class EventForm(forms.ModelForm):
#Events form fields here...
class Meta:
model = Event
fields = ["Event's field"]
EventFormSet = inlineformset_factory(Calender, Event, form=EventForm,
max_num=1, can_delete=False)
Render this formset with a view for student to create their events,the formset automatically associate student's event to calendar.
So you can add your logic to do more.
I need help with solving an issue regarding duplicate database query's for each form in an inlineformset. I have a page where users can add and edit books belonging to an author.
models.py
from django.db import models
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
class Book(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
category_idcategory = models.ForeignKey(Category, models.DO_NOTHING)
class Category(models.Model):
name = models.CharField(max_length=100)
forms.py
from django import forms
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
views.py
instance = get_object_or_404(Author, id=id)
form = inlineformset_factory(Author, Book, form=BookForm, can_delete=True, extra=5)
formset = form(request.POST or None, instance=instance)
if request.method == "POST":
if formset.is_valid():
instanceForm = formset.save(commit=False)
for obj in instanceForm:
obj.save()
for obj in formset.deleted_objects:
obj.delete()
return HttpResponseRedirect(URL)
When I run the template, it performs a database query to the Category model for each form in formset. How do I prevent those duplicates? I dont know where to put select_related or prefetch_related. If instances of Book model grows to a large number, the page load times are getting very slow.
template.html
<table class="table table-sm">
{{ formset.management_form }}
<thead>
<td>Title</td>
<td>Category</td>
<td>delete</td>
</thead>
<tbody>
{% for obj in formset %}
{{ obj.id }}
<tr>
<td>{{ obj.title }}</td>
<td>{{ obj.category_idcategory }}</td>
<td>{{ obj.DELETE }}</td>
</tr>
{% endfor %}
</tbody>
</table>
You can change the queryset of a formset like this:
class InlineBookFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Here is where to put the select_related.
self.queryset = Book.objects.select_related('category_idcategory').all()
then in your factory method call:
# Use your custom InlineBookFormSet
form = inlineformset_factory(Author, Book, form=BookForm, can_delete=True, extra=5, formset=InlineBookFormSet)
I've looked at several answers here and I can't get this to work. I'm trying to create a model form that will save the user's profile after he has signed up on the website. The problem is that when I try to render the form I get a blank page and no errors. Any help will be much appreciated.
models.py
class Perfil(models.Model):
user = models.OneToOneField(User)
Sexo = models.CharField(max_length=100)
Direccion = models.CharField(max_length=100)
CP = models.CharField(max_length=100)
Ciudad = models.CharField(max_length=100)
Estado = models.CharField(max_length=100)
Pais = models.CharField(max_length=100)
Telefono = models.CharField(max_length=100)
Celular = models.CharField(max_length=100)
PaisPasaporte = models.CharField(max_length=100)
NumeroPasaporte = models.CharField(max_length=100)
VigenciaPasaporte = models.DateField(max_length=100)
ContactoEmergencia = models.CharField(max_length=100)
TelefonoEmergencia = models.CharField(max_length=100)
CorreoEmergencia = models.CharField(max_length=100)
Alergias = models.CharField(max_length=500)
forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Perfil
views.py
#verified_email_required()
def profile(request):
if request.method == "POST":
form = ProfileForm(request.POST)
if form.is_valid():
perfil = form.save(commit=False)
perfil.user = request.user
perfil.save()
return HttpResponseRedirect("/profile/")
else:
return render(request, "explore/profile.html", {"form": form})
return render(request, "explore/profile.html")
and finally my html
<form class="profile" id="profile_form" method="post" action="" style="width: 50%;">
{% csrf_token %}
{% for field in form %}
<table>
<colgroup>
<col style="width: 45%;">
<col style="width: 10%;">
<col style="width: 45%;">
</colgroup>
<tr>
<td>{{ field.label_tag }}</td>
<td></td>
<td>{{ field }}</td>
</tr>
</table>
{% endfor %}
</form>
Thanks!
You are sending the form in the context only when request type is POST. The first time the page loads, by default it is a GET request. Hence the issue
Something like this should work:
def profile(request):
form = ProfileForm()
if request.method == "POST":
form = ProfileForm(request.POST)
if form.is_valid():
perfil = form.save(commit=False)
perfil.user = request.user
perfil.save()
return HttpResponseRedirect("/profile/")
return render(request, "explore/profile.html" {'form': form})
Note that you dont need the else clause at all - if the form is invalid, it automatically sends the erroneous form in the context, and your error messages are displayed just fine.