Create modelform from multiple models to add to database? - python

In my postgressql database I have tables:
class Topic(models.Model):
Definition = models.TextField(default='Definition')
Name = models.TextField(default='Name')
def __str__(self):
return self.Name
class Question(models.Model):
Statement = models.TextField(default='Question')
def __str__(self):
return self.Statement
class Planit_location(models.Model):
Planit_location = models.CharField(max_length=255, default='Planit_location')
def __str__(self):
return self.Planit_location
class ClientDetail(models.Model):
Sector = models.ForeignKey(Sector, on_delete=models.CASCADE)
Client_name = models.CharField(max_length=255, default='Client_name')
def __str__(self):
return self.Client_name
class Response(models.Model):
Question = models.ForeignKey(Question, on_delete=models.CASCADE)
Topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
Response = models.TextField(default='Response')
Client = models.ForeignKey(ClientDetail, on_delete=models.CASCADE)
Planit_Location = models.ForeignKey(Planit_location, on_delete=models.CASCADE)
Image = models.ForeignKey(Image, on_delete=models.CASCADE)
def __str__(self):
return self.Response
I want to create a modelform using all these tables so I can add new questions and responses to my database, which are then linked to a topic, location and client (these 3 will be a dropdownlist from data in db).
I have managed to create a modelform for just question and response but when I try to submit it I get "null value in column "Question_id" violates not-null constraint"
Here is the code:
if request.method == 'POST':
qform = QuestionForm(request.POST)
rform = ResponseForm(request.POST)
if qform.is_valid() and rform.is_valid():
qf = qform.save()
rf = rform.save()
return render(request, 'app/adddatatest.html', {
"qform": QuestionForm(),
"rform": ResponseForm(),
})

After checking for is_valid() in view do this:
qf = qform.save() # Goes to database
rf = rform.save(commit=False) # Doesn't goes to database
rf.Question = qf # gets required attribute
rf.save() # then goes to database
You can't save Response object without specifying the the foreign key Question. So in rform.save pass argument commit=False to not actually saving it in database yet. Then add the value for the foreign key to the new created Response object, foreign key is required otherwise you will get IntegrityError. Then finally save it to the database.

Related

Django Filter name "todo__test" is not defined

I'm trying to filter my Todos by the test_id pulled from the URL. It pulls the id from the URL but it cant seem to filter with todo__test. I have also tried "test", "Todo.test.test_id", "Todo.test". I guess I'm confused about what variable I need to filter and the Django restframework documentation doesn't explicitly show what variable to use. Their example uses "purchaser__username" which I don't understand where it comes from. https://www.django-rest-framework.org/api-guide/filtering/
class TodoList(generics.ListAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
def get_queryset(self):
test_id = self.kwargs['test_id']
return Todo.objects.filter(todo__test == test_id)
class Todo(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE)
content = models.TextField(blank=True)
order = models.IntegerField()
def __str__(self):
return self.content + ' - ' + self.test.test_name
class Meta:
ordering = ['test_id']
i guess it will be like this. you passed incorrect foreign key field name.
Todo.objects.filter(test_id='whatever_value')

The instant type changes to int in Foreign Key in Django

This is my models.py in django
class Site(models.Model):
# Site ID
siteID = models.CharField(max_length=255, null=True, unique = True)
def __str__(self):
return "{} ".format(self.siteID,)
class EndDevice(models.Model):
edevID = models.CharField(max_length=255)
siteID = models.ForeignKey(Site, on_delete=models.CASCADE)
deviceCategory = models.BigIntegerField()
And this is the method to post in views.py:
class RegisterSite(generics.ListAPIView):
'''
GET site/
POST site/
'''
queryset = Site.objects.all()
serializer_class = DataSerializer
# POST Regisger Site
def post(self, request, *args, **kwargs):
a_site = Site.objects.create(
siteID=request.data["siteID"],
# edevID=request.data["edevID"]
)
return Response(
data=DataSerializer(a_site).data,
status=status.HTTP_201_CREATED
)
class RegisterDevice(generics.ListAPIView):
'''
GET device/
POST device/
'''
queryset = EndDevice.objects.all()
serializer_class = DeviceSerializer
def post(self, request, *args, **kwargs):
siteID, created = Site.objects.get_or_create(
siteID=request.data["siteID"],
)
a_site = EndDevice.objects.create(
edevID=request.data["edevID"],
siteID = siteID,
deviceCategory=request.data["deviceCategory"],
)
return Response(
data=DeviceSerializer(a_site).data,
status=status.HTTP_201_CREATED
)
So what I am trying t do here is use the siteID from class Site for class EndDevice. But when I enter/ chose the value of siteID in Enddevice it changes to integer value. I checked the data base and it shows me int as its (siteID in EndDevice) characteristics. I was wondering how could I get the real value of siteID instead of an integer value.And I can accept character values while posting for class Site.
If the question is vague or unclear, please update me.
Thanks
EDIT
enter image description here
The serializer looks like:
class DataSerializer(serializers.ModelSerializer):
class Meta:
model = Site
fields = ("siteID",)
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = EndDevice
fields = ("edevID", "siteID", "deviceCategory")
Q:
when I enter/ chose the value of siteID in Enddevice it changes to integer value
Well the reason why it gets converted to int is because you haven't specified your own primary key field so Django uses its default primary key as Id field which is an integer field.
A:
Inside of Site model change this:
siteID = models.CharField(max_length=255, null=True, unique = True)
to this:
siteID = models.CharField(max_length=255, primary_key = True)
Now what that does is that it sets siteID as your primary_key instead of django's default Id.
See the docs

how can we query foreign key and get results of objects which are connected to foreign key

How can I can use managers to query my foreign key and then retrieve objects that are connected to foreign key?
Here is my models.py:
from django.db import models
# Create your models here.
class BookManager(models.Manager):
def title_count(self,keyword):
return self.filter(title__icontains=keyword).count()
class CategoryManager(models.Manager):
def category_count(self):
return self.filter(category__icontains=python).count()
class Category(models.Model):
title=models.CharField(max_length=20)
def __str__(self):
return self.title
class Enquiry(models.Model):
title=models.CharField(max_length=200)
category=models.ForeignKey(Category ,default=False,blank=False)
detail=models.TextField()
objects = BookManager()
objects=CategoryManager()
# tags=models.ChoiceField()
def __str__(self):
return self.title
I tried to use category manager but it gave me a strange error.
I just want to know how exactly we can get the objects that are connected with category foriegn-key and show them as list to the users.
You can combine both the title_count and category_count methods under one Manager. When filtering through a ForeignKey, your field lookup needs to specify the name of the field you're trying to filter on, else it will assume you're querying the ID field. So instead of category__icontains, you would do category__title__icontains.
Another note, in newer versions of Django, you are required to specify the on_delete parameter when defining a ForeignKey.
This is a working example of what I think you're trying to accomplish.
class BookManager(models.Manager):
def title_count(self, keyword):
return self.filter(title__icontains=keyword).count()
def category_count(self, keyword):
return self.filter(category__title__icontains=keyword).count()
class Category(models.Model):
title = models.CharField(max_length=20)
def __str__(self):
return self.title
class Enquiry(models.Model):
title = models.CharField(max_length=200)
category = models.ForeignKey(Category,
default=False,
blank=False,
on_delete=models.CASCADE)
detail = models.TextField()
books = BookManager()
# tags=models.ChoiceField()
def __str__(self):
return self.title
Here's how you would use it:
Enquiry.books.category_count('python')
Enquiry.books.title_count('test')

"No such column" error during deletion of a record in Django admin

I have following model (models.py) in my Django project:
class Topic(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=140)
def __unicode__(self):
return self.title
class ArgumentElement(models.Model):
id = models.AutoField(primary_key=True)
contents = models.CharField(max_length=256)
elementType = models.CharField(max_length=10)
topic = models.ForeignKey(Topic, related_name='ArgumentElement_Topic')
def __unicode__(self):
return self.contents
class ArgumentElementConnection(models.Model):
id = models.AutoField(primary_key=True)
sourceId = models.ForeignKey(ArgumentElement, related_name='connection_source')
targetId = models.ForeignKey(ArgumentElement, related_name='connection_target')
topic = models.ForeignKey(Topic, related_name='ArgumentElementConnection_Topic')
connectionType = models.CharField(max_length=7)
def __unicode__(self):
return self.id
I add all three models to the admin (admin.py):
from django.contrib import admin
from history_site.opinions.models import ArgumentElement, ArgumentElementConnection, Topic
admin.site.register(ArgumentElement, admin.ModelAdmin)
admin.site.register(ArgumentElementConnection, admin.ModelAdmin)
admin.site.register(Topic, admin.ModelAdmin)
When I create an instance of Topic and then try to delete it in the Admin, I get the error no such column: opinions_argumentelement.topic_id.
What's wrong with my models.py?
It seems that AutoFields using the sqllite3 backend don't increment properly. Is there any reason you are including the line id = models.AutoField(primary_key=True) ? If you leave it out, an auto-increment primary key field will be automatically added and is more likely to be correctly created. Try deleting that line and creating a new sqllite database file.

Django UpdateView wont delete tha old entry if primary key is edited

So lets say we have this model:
class Student(models.Model):
am = models.SmallIntegerField(unique=True, primary_key=True) # XXX: max_value = 10000
date_enrolled = models.DateField('Date Enrolled')
semester = models.IntegerField(default=1)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
undergraduate = models.BooleanField(default=True)
An update view like this:
class StudentUpdateView(SqlPresenterMixin, StudentMixin, UpdateView):
model = Student
form_class = StudentForm
template_name = "profapp/student_form.html"
slug_field = "am"
Then this test fails:
class TestStudent(TestCase):
def setUp(self):
self.c = Client()
Student.objects.create(am=2222, first_name="Chris",
last_name="Perivolas",
date_enrolled=datetime.date(year=2010, day=15,
month=2))
Student.objects.create(am=7362, first_name="Mary",
last_name="Karagewrgena",
date_enrolled=datetime.date(year=2010, day=15,
month=2))
def test_update(self):
"""
"""
r = self.c.post("/profapp/students/2222/update/",
dict(am=7363, first_name="Chris",
last_name="Perivolas",
date_enrolled="3/15/2010",
semester=2,
undergraduate=1))
self.assertEquals(Student.objects.filter(am=2222).exists(), False)
In short update view doesn't delete the old entry when updating a primary key. What is the best way of solving this?
According to Django documentation, PK should never change. PK is what ties your object to a specific row in the DB. When you change the PK, Django loses the connection to the original row in the DB and assumes that you want to create another row.
You should add another field to act as changeable id if you really need it.

Categories