Django Foreign Keys connections - django

I have a model Field that has a OneToMany connections with TreeSensor and WeatherStation model. Im trying to pass over the queries of each treesensor/weatherstation model that match the id of each different field but get a Field 'id' expected a number but got <built-in function id>. .How do i fix that? Maybe change something on the filter ?
class Field(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True, default=None)
friendly_name = models.CharField(max_length=24, blank=True)
soil_type = models.CharField(max_length=24, choices=SOIL_TYPES, blank=True)
cultivation = models.CharField(max_length=128, choices=CULTIVATIONS, blank=True)
kml = models.FileField(upload_to = user_directory_path_kml, null=True, blank=True)
class TreeSensor(models.Model):
field = models.ForeignKey(Field, on_delete=models.CASCADE)
...
class WeatherStation(models.Model):
field = models.ForeignKey(Field, on_delete=models.CASCADE)
...
view
def map(request):
field_list = models.Field.objects.filter(user = request.user)
tree_sensors = models.TreeSensor.objects.filter(field__pk = id)
weather_stations = models.WeatherStation.objects.filter(field__pk = id)
context = {
"title": "Map",
"field_list": field_list,
"tree_sensors": tree_sensors,
"weather_stations" : weather_stations,
}
template = 'agriculture/map.html'
return render(request, template, context)

On your view you are filtering some field called field by id, which is not defined nowehere....
You have a queryset of Fields, so probably you should do something like this:
def map(request):
field_list = models.Field.objects.filter(user = request.user).values_list('id', flat=True)
tree_sensors = models.TreeSensor.objects.filter(field__id__in = field_list)
weather_stations = models.WeatherStation.objects.filter(field__id__in = field_list)

#Walucas your approach was correct it was kinda different though . It works out like this :
view
def map(request):
field_list = models.Field.objects.filter(user = request.user)
tree_sensors = models.TreeSensor.objects.filter(field_id__in = field_list.values_list('id',flat=True))
weather_stations = models.WeatherStation.objects.filter(field_id__in = field_list.values_list('id',flat=True))
context = {
"title": "Map",
"field_list": field_list,
"tree_sensors": tree_sensors,
"weather_stations" : weather_stations,
}
template = 'agriculture/map.html'
return render(request, template, context)

Related

How can I obtain just one JSON object with the three models information combined?

How can I pass the foreign key values from my model to my serialised json object?
Now I have this three models,
class Fleet(models.Model):
fleet_id = models.IntegerField('Id flota', primary_key=True, unique=True)
fleet_name = models.CharField('Nombre flota', max_length=20, unique=True)
def __str__(self):
return self.fleet_name + ' ' + str(self.fleet_id)
class Device(models.Model):
dev_eui = models.CharField(max_length=16, primary_key=True, unique=True)
producer = models.CharField(max_length=20)
model = models.CharField(max_length=20)
dev_name = models.CharField(max_length=20, unique=True)
fleet_id = models.ForeignKey(Fleet, on_delete=models.CASCADE)
def __str__(self):
return self.dev_eui
class DevData(models.Model):
data_uuid = models.UUIDField(primary_key=True, default=uuid.uuid1, editable=False)
frequency = models.IntegerField()
data_1 = models.FloatField()
data_2 = models.FloatField(null=True, blank=True)
dev_eui = models.ForeignKey(Device, on_delete=models.CASCADE) #hay que saber porque aƱade _id
def __str__(self):
return self.dev_eui
And what I'm doing is call my view function in my JS code to obtain some data like this.
def getData(request):
ctx = {}
if request.method == 'POST':
select = int(request.POST['Select'])
data = DevData.objects.order_by('dev_eui','-data_timestamp').distinct('dev_eui')
nodes = Device.objects.all()
fleets = Fleet.objects.all()
data = loads(serializers.serialize('json', data))
nodes = loads(serializers.serialize('json', nodes))
fleets = loads(serializers.serialize('json', fleets))
ctx = {'Data':data, 'Nodes':nodes, 'Fleets':fleets}
return JsonResponse(ctx)
And inside my js file I filter it with some if else conditionals.
This works well, but I'm sure I can do it directly in my view but I don't know how. How can I obtain just one JSON object with the three models information combined?
Thank you very much!!
You can write a custom serializer like this:
from django.core.serializers.json import Serializer
class CustomSerializer(Serializer):
def end_object(self, obj):
for field in self.selected_fields:
if field == 'pk':
continue
elif field in self._current.keys():
continue
else:
try:
if '__' in field:
fields = field.split('__')
value = obj
for f in fields:
value = getattr(value, f)
if value != obj and isinstance(value, JSON_ALLOWED_OBJECTS) or value == None:
self._current[field] = value
except AttributeError:
pass
super(CustomSerializer, self).end_object(obj)
Then use it like this
serializers = CustomSerializer()
queryset = DevData.objects.all()
data = serializers.serialize(queryset, fields=('data_uuid', 'dev_eui__dev_eui', 'dev_eui__fleet_id__fleet_name'))
I have wrote an article regarding serializing nested data here. You can check that out as well.

Django - Update a record using a modelform (Table contains Unique_constraint)

The idea would be that the user should be able to go in and update the record using the same form I have provided. I included a unique constraint because the idea was that a Requisition can contain multiple Requisition_lines. For the initial phase I have hard coded sequence=1. It saved the record initially but I am now getting an Integrity error when i try to update the record using update_or_create. Any help would be appreciated! Let me know if any more information is needed.
Models.py
class Requisition(models.Model):
username = models.ForeignKey(
'users.CustomUser', on_delete=models.CASCADE, related_name='req_user')
signature = models.CharField(max_length=10, blank=True, null=True)
status = models.ForeignKey('RequisitionStatus', related_name='req_status', on_delete=models.CASCADE)
class RequisitionLine(models.Model):
parent_req = models.ForeignKey('Requisition', on_delete=models.CASCADE, related_name='par_req_line' )
sequence = models.PositiveIntegerField()
item_code = models.ForeignKey(
'items.ItemMaster', on_delete=models.CASCADE, related_name='req_item', blank=True, null=True)
description = models.CharField(max_length=50, blank=True)
extra_information = models.TextField(blank=True)
quantity = models.PositiveIntegerField(blank=True, default=0,null=True)
price = models.DecimalField(max_digits=19, decimal_places=2, blank=True, default=0.00,null=True)
purchase_order = models.CharField(max_length=9, blank=True,null=True)
po_line = models.PositiveSmallIntegerField(blank=True,null=True)
req_delivery_date = models.DateField(blank=True,null=True)
act_delivar_date = models.DateField(blank=True, null=True)
class Meta:
unique_together = ('parent_req','sequence')
Views.py
def update_requisition(request, id):
current_req = Requisition.objects.get(id=id)
if current_req.username == request.user:
data = { 'parent_req': id }
if request.method == "POST":
req_form = ReqForm(request.POST, instance = current_req)
if req_form.is_valid():
req_form_line, created = RequisitionLine.objects.update_or_create(
parent_req = current_req,
sequence = 1,
description = req_form.cleaned_data['description'],
extra_information = req_form.cleaned_data['extra_information'],
quantity = req_form.cleaned_data['quantity'],
price = req_form.cleaned_data['price'],
defaults = {'parent_req':current_req,
'sequence': 1 })
return(redirect(reverse('requisition:req_history')))
else:
try:
req_form_line = RequisitionLine.objects.get(parent_req=current_req, sequence=1)
req_form = ReqForm(initial=data, instance = req_form_line)
except RequisitionLine.DoesNotExist:
req_form = ReqForm(initial=data, instance = current_req)
return render(request, 'req/update_req.html' , {'current_req': current_req, 'req_form': req_form})
else:
return HttpResponseRedirect(reverse('requisition:req_history'))
Your usage of the update_or_create function is wrong. You misunderstand the keyword defaults (see docs). You need to put all your fields to update into this dictionary:
req_form_line, created = RequisitionLine.objects.update_or_create(
parent_req = current_req,
sequence = 1,
defaults = {
description : form.cleaned_data['description'],
extra_information : req_form.cleaned_data['extra_information'],
quantity : req_form.cleaned_data['quantity'],
price : req_form.cleaned_data['price'],
})

I am trying to create a django query that returns the posts that are of post_type "mobiles"

class Entry(models.Model):
title = models.CharField(max_length=200)
post_type = models.CharField(max_length=50, default="others")
author = models.CharField(max_length=30, default = "")
body = models.TextField()
slug = models.SlugField(max_length = 200, unique = True)
publish = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now_add=True)
objects = EntryQuerySet.as_manager()
def __str__(self):
return self.title
class Meta:
verbose_name = "Blog Entry"
verbose_name_plural = "Blog Entries"
ordering = ["-created"]
The above code is my models.py
class MobilesIndex(generic.ListView):
queryset = models.Entry.objects.get(post_type="Mobile")
template_name = "index.html"
paginate_by = 5
def Mobiles(request):
context = locals()
template = "Mobiles.html"
return render(request,template,context)
The above code is view.py
how do i write the query that has only the posts that are of post_type="Mobile"
Try :
Entry.objects.fitler(post_type="Mobile")
get() return ONE object or exeception if not exists/multiple objects, but filter() returns all objects (or None if no objects).
queryset = models.Entry.objects.filter(post_type="Mobile")
this will give you all the post type and to render in template you need to loop it

Making table report from non-related GeoDjango models

I have this 2 models:
class BuildingStructure(models.Model):
bldg_name = models.CharField(max_length=100)
height = models.FloatField()
code = models.CharField(max_length=25)
block_name = models.CharField(max_length=75)
bldg_type = models.CharField(max_length=50)
brgy_locat = models.CharField(max_length=50)
geom = models.MultiPointField(srid=32651, null=True, blank=True)
objects = models.GeoManager()
def __unicode__(self):
return self.bldg_name
class FloodHazard(models.Model):
gridcode = models.IntegerField()
hazard = models.CharField(max_length=6)
date_field = models.CharField(max_length=50)
geom = models.MultiPolygonField(srid=32651, null=True, blank=True)
objects = models.GeoManager()
def __unicode__(self):
return self.hazard
hazard field in the model has the following values: 'High', 'Medium', 'Low'.
I wanted to create a report in a table format(HTML) like this:
I tried this so far:
getgeom = FloodHazard.objects.get(id=512).geom
getgeom_medium = FloodHazard.objects.get(id=620).geom
getgeom_low = FloodHazard.objects.get(id=638).geom
response_data = {}
response_data["medium"] = list(BuildingStructure.objects.filter(geom__intersects=getgeom_medium).values( 'brgy_locat').annotate(countmedium=Count('brgy_locat')))
response_data["high"] = list(BuildingStructure.objects.filter(geom__intersects=getgeom).values('brgy_locat').annotate( counthigh=Count('brgy_locat')))
response_data["low"] = list(BuildingStructure.objects.filter(geom__intersects=getgeom_low).values('brgy_locat').annotate( countlow=Count('brgy_locat')))
result = {}
for category in response_data.values():
for element in category:
key = element.pop('brgy_locat')
if key not in result:
result[key] = {"loc":key}
result[key].update(element)
json_result = result.values()
return HttpResponse(list(json.dumps(json_result)), content_type='application/json')
The above code works fine as I am able to get my intended output. But as you examine it, I tried one id in each hazard type. So my problem now is to use filter to get all the ids and used it as reference in my GeoQuerySet. Any help will be appreciated. I'm trying to pass the data as JSON in my template because I'm using datatables.
This is how I get all the ids for e.g. hazard type "high"
reference = FloodHazard.objects.filter(hazard='High')
ids = reference.values_list('id', flat=True)
for id in ids:
#something has to be done here...

Cannot assign "u''": "Company.parent" must be a "Company" instance

I am getting this at every attempt.
Cannot assign "u''": "Company.parent" must be a "Company" instance.
I do not know what else to do.
The view code is still half baked, sorry for that.
Am I passing wrong parameters to the form?
I have the following model:
models.py
class Company(AL_Node):
parent = models.ForeignKey('self',
related_name='children_set',
null=True,
db_index=True)
node_order_by = ['id', 'company_name']
id = models.AutoField(primary_key=True)
company_name = models.CharField(max_length=100L, db_column='company_name') # Field name made lowercase.
next_billing_date = models.DateTimeField()
last_billing_date = models.DateTimeField(null=True)
weekly = 'we'
twice_a_month = '2m'
every_two_weeks = '2w'
monthly = 'mo'
billing_period_choices = (
(weekly, 'Weekly'),
(every_two_weeks, 'Every two weeks'),
(twice_a_month, 'Every two weeks'),
(monthly, 'Monthly'),
)
billing_period = models.CharField(max_length=2,
choices=billing_period_choices,
default=weekly)
objects = CompanyManager()
The following forms.py:
class newCompany(ModelForm):
company_name = forms.CharField(label='Company Name',
widget=forms.TextInput(attrs={'class': 'oversize expand input-text'}))
billing_period = forms.ModelChoiceField
next_billing_date = forms.CharField(widget=forms.TextInput(attrs={'class': 'input-text small', 'id': 'datepicker'}))
parent = forms.CharField(widget=forms.HiddenInput(), required=False)
class Meta:
model = Company
fields = ["company_name", "parent", "billing_period", "next_billing_date"]
The following view:
def create_company(request):
userid = User.objects.get(username=request.user).id
my_company_id = CompanyUsers.objects.get(user_id=userid).company_id
my_company_name = Company.objects.get(id=my_company_id).company_name
machines = Title.objects.raw(
'select machines.id, title.name, machines.moneyin, machines.moneyout, moneyin - moneyout as profit, machines.lastmoneyinoutupdate, (select auth_user.username from auth_user where machines.operator = auth_user.id) as operator, (select auth_user.username from auth_user where machines.readers = auth_user.id) as readers from machines, title where machines.title = title.id and machines.company_id =%s',
[my_company_id])
if request.method == 'POST':
form_company = newCompany(request.POST)
if form_company.is_valid():
new_company = form_company.save(commit=False)
new_company.parent = my_company_id
if request.POST.get('select_machine'):
selected_machine = request.POST.getlist('select_machine')
percentage = request.POST.get('percentage')
if not Beneficiary.objects.check_assign_machine(my_company_id, selected_machine, percentage):
target_company_name = new_company.company_name
target_company_id = Company.objects.get(company_name=target_company_name).id
new_company.save()
Machines.objects.assign_machine(target_company_id, selected_machine)
Beneficiary.objects.create_beneficiary(percentage, target_company_name, my_company_id, selected_machine)
else:
invalid_machines = Beneficiary.objects.check_assign_machine(my_company_id, selected_machine, percentage)
return render(request, 'lhmes/createcompany.html',
{'form_company': form_company, 'machines': machines, 'my_company_name': my_company_name, 'invalid_machines' : invalid_machines})
else:
new_company.save()
else:
form_company = newCompany()
return render(request, 'lhmes/createcompany.html',
{'form_company': form_company, 'machines': machines, 'my_company_name': my_company_name})
The error message says you are trying to set a relationship with a string but Django expects the value to be an instance of the Company model. You should assign the foreign key fields with a real model instance instead of only the primary key.
I've spotted a few places in the code where you are assigning a PK:
new_company.parent = my_company_id
Where the model expects it to be an instance:
new_company.parent = Company.objects.get(id=my_company_id)
I really don't remember if this works, but you can try:
new_company.parent_id = int(my_company_id)
This would spare a trip to the database.