I'm creating a page that lets only admin add some assets. Each asset has a type. I have used a dropdown to select the asset_type. The selected value of asset_type gets passed into views.py but I can't get it written into the newly created asset object.
Here is my models.py
class assetType(models.Model):
title = models.CharField(max_length=150)
#property
def get_type(self):
return asset.objects.filter(asset_type=self.id)
def __str__(self):
return f"{self.title}"
class Meta:
verbose_name_plural = 'Asset Types'
class asset(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, null=False)
asset_type = models.ForeignKey('assetType', on_delete=models.CASCADE, null=True)
asset_name = models.CharField(max_length=30, null=True) #unique=True
location = models.CharField(max_length=30, null=True)
brand = models.CharField(max_length=30, null=True)
purchase_year = models.PositiveIntegerField(blank=True, null=True)
isActive = models.BooleanField(default=True, null=True)
currentOwner = models.ForeignKey(User, default='', null=True, on_delete=models.CASCADE)
Here is createAssetView from views.py
#user_passes_test(lambda u: u.is_superuser)
def createAssetView(request):
assetTypeList = assetType.objects.all() # use assetType.title
assettype = request.POST.get('asset-type')
assetname = request.POST.get('asset-name')
locationn = request.POST.get('location')
brandd = request.POST.get('brand')
purchaseyear = request.POST.get('purchase-year')
isActivve = request.POST.get('is-active','') == 'on'
cuser=request.user
context={
"cuser":request.user,
"asset_type_list":assetTypeList,
"asset_type":assettype,
"asset_name":assetname,
"location":locationn,
"brand":brandd,
"purchase_year":purchaseyear,
"isActive":isActivve,
'iterator':range(2014,2050)
}
if request.method == 'POST':
new_asset = asset()
new_asset.asset_type_title=request.POST.get('asset-type')
new_asset.asset_name=assetname
new_asset.location=locationn
new_asset.brand=brandd
new_asset.purchase_year=purchaseyear
new_asset.isActive=True if isActivve else False
new_asset.currentOwner=cuser
print(assettype) # PRINT assettype
new_asset.save()
return redirect('createAssets')
return render(request, 'assets/createAsset.html', context)
The PRINT assettype statement prints selected asset type from the form, so the value is getting passed to the view, how should I populate the table with it?
Any suggestions or help will be highly appreciated. Thanks!
new_asset.asset_type_title=request.POST.get('asset-type')
This is the line where your problem is. You can't assign a foreign object like that, it does not automatically search for a match in another model.
You need to either provide the object to be used as a foreign key, or the object's primary key.
So we find our database entry for the selected type:
target_type = assetType.objects.get(title=assettype)
# this assumes you use unique titles for each assetType, see below
and then provide the new asset either with the object itself:
new_asset.asset_type = target_type
or its primary key:
new_asset.asset_type_id = target_type.pk
I strongly reccomend spending more time with django's documentation to strengthen your understanding of how foreign object relation is implemented in django. At least review the tutorials that focus on that.
Also consider the following:
The title field of the assetType model is not limited to be unique. What happens if two assetTypes with the same title are created?
Repetition of request.POST.get('asset-type')
Related
I am having a problem in editing a page in my code.
Basically I have a page where I have multiple select field where I can select the students. But I have a problem in understanding how to remove a specific student, if I need to edit this page. Let me be more clear with some code.
models.py
class TheorySyllabus(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
subject_duration = models.ManyToManyField(
SubjectDuration, related_name='theory_syllabus')
course_type = models.ForeignKey(
CourseType, on_delete=models.DO_NOTHING, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Theory Syllabus'
class TheoryCourse(models.Model):
name = models.CharField(max_length=100)
student = models.ManyToManyField(Student, related_name='theory_courses')
theory_syllabus = models.ForeignKey(
TheorySyllabus, on_delete=models.DO_NOTHING, null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
views.py
def edit_theory_course(request, pk):
theory_course = TheoryCourse.objects.get(id=pk)
student_obj = theory_course.student.all()
theory_syllabus = TheorySyllabus.objects.all()
students = Student.objects.filter(is_active=True).order_by('last_name')
context = {
'theory_course': theory_course,
'theory_syllabus': theory_syllabus,
'students': students,
'student_obj': student_obj,
}
if request.method == 'POST':
course_name = request.POST.get('course_name')
student = request.POST.getlist('student')
syllabus = request.POST.get('syllabus')
try:
theory_course.name = course_name
theory_course.theory_syllabus_id = syllabus
theory_course.save()
for stud in student:
theory_course.student.add(stud)
theory_course.save()
messages.success(request, "Theoretical Course Edited")
return HttpResponseRedirect(reverse('theory:course_list'))
except:
messages.error(request, "Failed to Edit Theoretical Course")
return HttpResponseRedirect(reverse('theory:edit_theory_course', kwargs={'pk': pk}))
return render(request, 'theory/edit_theory_course.html', context)
I know that basically, what I need to do is in the view to place an if statement to compare the two lists and remove (if needed) the value that is not part of the entry list anymore. The problem is that I have no clue how to place this logic.
Any help is highly appreciated.
Thank you very much
I think you can replace the full list of students at once by doing theory_course.student.set([list_of_student_pks])
A very clean and easy way to accomplish this is to make a query for all of the current students (which you don't even need to do since it's already in theory_course), then just simply get the difference between the students in that query and the submitted students. This will yield you the students that were removed, which you can then iterate over and delete.
current_students = theory_course.students
selected_students = Student.objects.filter(pk__in=student)
removed_students = current_students.difference(selected_students)
for s in removed_students:
s.delete()
There is however an option to set all of the IDs at once using and Object's set() method, but having the list of removed users so that you can make necessary changes (such as sending emails) is much better from my experience.
views.py :
def dcuinterval(request):
var7 = dcu.objects.all()
MU_count = Meter_Mapping_Table.objects.filter(DCU_id=dcu.id).count()
d = {
'MU_count': MU_count, 'var7': var7,
}
return render(request, 'dcu_interval.html', d)
Models.py:
class dcu(models.Model):
id = models.AutoField(unique=True, editable=False, primary_key=True)
Asset = models.CharField(max_length=128)
IMEI_Number = models.CharField(max_length=128)
def __str__(self):
return self.Asset
class Meter_Mapping_Table(models.Model):
mid = models.AutoField(unique=True, editable=False, primary_key=True)
Meter_id = models.CharField(
max_length=128, help_text='(ID of the Meter table)')
MU_id = models.CharField(max_length=150)
DCU_id = models.CharField(max_length=150, null=True, blank=False)
def __str__(self):
return self.Meter_id
how to filter the data based on the another table filed ?
i need to filter the DCU_id based on the DCU tables id field
DCU_id =1;
DCU.id=1;
ANSWER:
MU_count=1
like this i need to filter and show that count
You can use:
Meter_Mapping_Table.objects.filter(DCU_id='1').count()
Although that is the answer, you need to really consider your database design and make use of ForeignKey relationships. Having a foreign key as a CharField is not recommended.
I would suggest the following:
Change:
DCU_id = models.CharField(max_length=150, null=True, blank=False)
To:
DCU = models.ForeignKey(dcu, null=True, blank=False)
Then you can query like so:
Meter_Mapping_Table.objects.filter(DCU=1).count()
Note: Also consider following Django's Naming Convention for Models. As this will aid readability for other developers.
I've been reading similar questions to mine but they didn't help me.
I'm getting this error while I try to submit my form:
Cannot assign "9": "Characterweapons.weaponid" must be a "Weapons" instance.
This "9" is the ID from the weapon I got from my form, so that's very good, but when I try to put it in my weaponid column in my table Characterweapons, it gives me the error.
models.py:
from __future__ import unicode_literals
from django.db import models
class Category(models.Model):
categoryid = models.AutoField(db_column='CategoryID', primary_key=True) # Field name made lowercase.
categoryname = models.CharField(db_column='CategoryName', max_length=50, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = True
db_table = 'category'
def __str__(self):
return self.categoryname
class Characters(models.Model):
characterid = models.AutoField(db_column='CharacterID', primary_key=True) # Field name made lowercase.
name = models.CharField(db_column='Name', unique=True, max_length=255) # Field name made lowercase.
level = models.IntegerField(db_column='Level') # Field name made lowercase.
credits = models.IntegerField(db_column='Credits') # Field name made lowercase.
class Meta:
managed = True
db_table = 'characters'
def __str__(self):
return '%s %s %s' % (self.name, self.level, self.credits)
class Weapons(models.Model):
weaponid = models.AutoField(db_column='WeaponID', primary_key=True) # Field name made lowercase.
weaponname = models.CharField(db_column='WeaponName', unique=True, max_length=255) # Field name made lowercase.
class Meta:
managed = True
db_table = 'weapons'
def __str__(self):
return '%s %r' % (self.weaponname, self.weaponid)
class Characterweapons(models.Model):
characterid = models.ForeignKey(Characters, models.DO_NOTHING, db_column='CharacterID') # Field name made lowercase.
weaponid = models.ForeignKey(Weapons, models.DO_NOTHING, db_column='WeaponID', blank=True, null=True) # Field name made lowercase.
categoryid = models.ForeignKey(Category, models.DO_NOTHING, db_column='CategoryID', blank=True, null=True) # Field name made lowercase.
quantity = models.IntegerField(db_column='Quantity', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = True
db_table = 'characterweapons'
def __str__(self):
return '%s' % (self.quantity)
class DjangoMigrations(models.Model):
app = models.CharField(max_length=255)
name = models.CharField(max_length=255)
applied = models.DateTimeField()
class Meta:
managed = True
db_table = 'django_migrations'
I don't know if it is a FK problem, PK... no idea and I cannot find information to solve it...
views.py: (where the error has to be):
def submission(request):
print("Registered successfully")
Name = request.POST["Name"]
Level = request.POST["Level"]
Credits = request.POST["Credits"]
Mainhand = request.POST["Mainhand"]
Offhand = request.POST["Offhand"]
info = Characters(name=Name,level=Level,credits=Credits)
info.save()
mh=
infomh = Weapons.objects.values_list('weaponid',flat=True)
a=0;
for a in infomh:
if a == Mainhand:
a = Mainhand;
print("a: ")
print(a)
print("Mainhand")
print(Mainhand)
print("infmh:")
print(infomh)
charid = Characters.objects.latest('characterid')
info_mh = Characterweapons(characterid=charid,categoryid=1,weaponid=a)
info_mh.save()
#info_oh = Characterweapons(characterid=charid,weaponid=9,categoryid=2)
#info_oh.save()
return return_charnames(request)
With these prints I made sure that the values of my weaponsID are correct, they are.
I also wanna point out that the value=9 in the column "weaponid" exists in "Weapons" table.
Thanks all.
I think you better first fix your models. In Django a ForeignKey is conceptually a reference to an object to which you refer, not the id. Of course in the database it is stored as an id, but that is a layer that you should not care much about.
So I would advice to first rename the fields like weaponid to weapon:
class Characterweapons(models.Model):
character = models.ForeignKey(Characters, models.DO_NOTHING, db_column='CharacterID')
weapon = models.ForeignKey(Weapons, models.DO_NOTHING, db_column='WeaponID', blank=True, null=True)
category = models.ForeignKey(Category, models.DO_NOTHING, db_column='CategoryID', blank=True, null=True)
quantity = models.IntegerField(db_column='Quantity', blank=True, null=True)
# ...
Now if you construct a ForeignKey with the name fieldname, Django actually introduces two fields: the fieldname which is - like said before - a reference to a model object to which the ForeignKey refers, and a field fieldname_id that stores the id (the primary key) of that object. These two fields thus act like "twins".
We can then rewrite the submission view like:
def submission(request):
print("Registered successfully")
name = request.POST["Name"]
level = request.POST["Level"]
credits = request.POST["Credits"]
mainhand = request.POST["Mainhand"]
offhand = request.POST["Offhand"]
info = Characters.objects.create(name=name, level=level,credits=credits)
if Weapons.objects.filter(weapon_id=mainhand).exists():
a = mainhand
info_mh = Characterweapons.objects.create(
character_id=info.pk,
category_id=1,
weapon_id=a
)
return return_charnames(request)
In the above I did some refactorings as well:
In Python variables in functions typically have lowercase names;
you do not need to loop over weapon_ids, you can use an EXISTS query, which is typically faster;
Instead of first constructing a model instance, and then obj.save() it, you can use Model.objects.create(..) instead;
you probably do not want to fetch the latest(..) value, but use the pk of the info object instead, since that is the one we constructed, and furthermore if there is no order defined (like here), the order can be any order the database likes, not per se the latest one added.
You probably still need to rewrite hardcoded identifiers (like a=1, and category_id=1, since it is perfectly possible that those objects do not exist in the database).
Your foreignkey weaponid in the model Characterweapons is a Weapon instance not only its id.
From that id, query the object and assign it.
I have an abstract model class userabstract which has fields id(primary key), name(char field) and email(email field).
I am inheriting this class in two classes user, usertemp. After signing up, i want the data to be stored in usertemp. When user clicks on confirmation mail then that data will be transferred to user class.
But whats happening is, whenever someone signs up, usertemp model is updated instead of creating a new one. Same thing is happening with user class
Here is the code for models and views
class UserAbstract(models.Model):
id = models.AutoField(db_column='ID', primary_key=True, default=1) # Field name made lowercase.
name = models.CharField(db_column='NAME', max_length=100, default='') # Field name made lowercase.
email = models.CharField(db_column='EMAIL', max_length=100, default='') # Field name made lowercase.
def __str__(self):
return self.name
class Meta:
abstract = True
#python_2_unicode_compatible
class User(UserAbstract):
def __str__(self):
return self.name ;
class Meta:
managed = True
db_table = 'User'
#python_2_unicode_compatible
class Validation(models.Model):
key = models.AutoField(primary_key=True)
key_data = models.CharField(max_length=100, default='')
create_time = models.DateTimeField()
expire_time = models.DateTimeField()
def __str__(self):
return self.key_data
#python_2_unicode_compatible
class UserTemp(UserAbstract):
validation_key = models.ForeignKey(Validation, models.DO_NOTHING, related_name='+', default='') # Field name made lowercase.
verified = models.BooleanField(default=False)
def __str__(self):
return self.validation_key.key_data
views.py
def signup(request):
if request.method == 'POST':
form = FormTemp(request.POST, request.FILES)
if form.is_valid():
primary = form.cleaned_data['email']
try:
qdict = {}
qdict['email'] = primary
user = UserTemp.objects.get(**qdict)
if user.verified==True:
return HttpResponse("Account already exists")
except:
pass
email = form.cleaned_data['email']
signer = hashlib.sha256()
signer.update(primary)
validation_key = signer.hexdigest()
confirm_key = request.build_absolute_uri('/signup-confirm/')+'?key='+validation_key
send_mail('Confirm Your Mail', confirm_key, settings.EMAIL_HOST_USER, [email,])
valid = Validation(key_data=validation_key, create_time=datetime.now(), expire_time=datetime.now()+timedelta(days=30))
valid.save()
argsdict = {}
argsdict['name'] = form.cleaned_data['name']
argsdict['email'] = form.cleaned_data['email']
argsdict['validation_key'] = valid
argsdict['verified'] = False
usertemp = UserTemp(**argsdict)
usertemp.save()
return HttpResponse("Confirmation mail sent")
else:
return HttpResponse('Invalid Data')
else:
return HttpResponse('What are you doing here ? Tresspass')
The valid.save() is working fine and every time validation key is being saved but the usertemp contains only one model and that is the most recent one.
When i tried force_insert=True then its telling me that duplicate entry exist with same primary key. As you can see, the primary key field id is AutoField then why django not creating a new model when i am writing usertemp = UserTemp(**argsdict)
The problem here is that you've given your AutoField a default value. You're telling Django to assign that field the value 1 if you don't provide it, which means that you keep writing rows with the same id.
So just get rid of that default.
The broader point to understand is that defaults are a Django-level feature, while AutoField is a database-level feature. From the perspective of the database, there's no difference between explicitly assigned column values and Django default column values.
I am trying to get a queryset but it is not displaying anything. Basically, I want to get the Asset objects that are assigned via foreign key to an employee, which is a foreign key of the signed in user.
views.py
def get_queryset(self):
assetlist = Asset.objects.filter(organisation__employee__user=self.request.user)
print(assetlist)
return assetlist
models.py
class Employee(models.Model):
name = models.CharField("Employee Name", max_length=50, blank=False)
email = models.CharField("Employee Email", max_length=50, blank=True)
user = models.ForeignKey(User)
clientID = models.ForeignKey(Organisation)
def save(self):
self.name = self.user.get_full_name()
self.email = self.user.email
super(Employee, self).save()
def __str__(self):
return self.name
class Asset(models.Model):
name = models.CharField("Asset Name", max_length=30, primary_key=True)
organisation = models.ForeignKey(Organisation)
def __str__(self):
return self.name
class Organisation(models.Model):
name = models.CharField("Organisation Name", max_length=50, blank=False)
location = models.TextField("Organisation Address", max_length=200, blank=True)
tel = models.CharField("Telephone Number", max_length=20)
def __str__(self):
return self.name
There is no employee field inside organisation. It's an reversed relation, there are many employees attached so you can't query it like that.
But there is something called related_name in django foreign keys, with use of that, your query should look like that:
assetlist = Asset.objects.filter(organisation__employee_set__user=self.request.user)
or if you specify your own related_name into employee -> organisation relation:
clientID = models.ForeignKey(Organisation, related_name="employees")
it will look like this:
assetlist = Asset.objects.filter(organisation__employees__user=self.request.user)
The answer was to approach from another model, as seen below:
assetlist = Sensor.objects.filter(asset__organisation__employee__user=self.request.user)
You have written wrong code. You want an Asset object by using:
assetlist = Asset.objects.filter(organisation__employee__user=self.request.user)
But you clearly can see in your models.py that there is no relationship between Organisation and Employee, then how can you get a result using organisation__employee...?
You should first create a ForeignKey field to relate with Employee model then your code will work fine.