django save model ForeignKey relation - django

in my model.py
class Layer(models.Model):
user = models.IntegerField()
name = models
...
class Point(models.Model):
layers = models.ForeignKey(Layer)
meta = models.TextField()
...
in my view.py
def datasave(request, id):
mid = request.POST.get("layerid",default = "")
metas = request.POST.get("meta",default = "")
cs = Point()
cs.layers = mid
cs.meta = metas
cs.save()
but it gives an error in my django debug..in my project i use geodjango,openlayers and extjs... i didnt find any solution about saving my post
i didnt make any relation with my foreignkey.. basically i want to make a layer than when i want to add a point in my layer , i want save my point with layer id....

A more efficient way is to specify the foreign key by adding an "_id" at the end, like this:
cs = Point(layers_id = mid, meta = metas)
cs.save()
DO NOT do layers=XXX.objects.get(id=###) because that's doubling the number of database queries.
ALSO ... you're not cleaning your POST data here, which is pretty dangerous. Get it like this:
from django import forms
id_field = forms.IntegerField()
layer_id = id_field.clean(request.POST.get("layerId", "")

It's helpful to post the traceback to help understand your problem (for future questions).
It looks to me like you are passing in a number to your Point instance's layers attribute which would cause a ValueError. The only place you can pass a number to a foreign key field is in a django form which does the lookup for you.
You need to assign an actual Layer instance instead.
cs = Point()
cs.layers = Layer.objects.get(id=mid)
cs.meta = metas
cs.save()

Related

How to Update models field based on another field of same models

class PurchaseOrder(models.Model):
purchase_order_id = models.AutoField(primary_key=True)
purchase_order_number = models.CharField(unique=True)
vendor = models.ForeignKey(Vendor)
i am creating Purchase Order(po) table. when po created i have to update purchase_order_number as "PO0"+purchase_order_id ex PO0123 (123 is Primary key). so i am using def save in models to accomplish this
def save(self):
if self.purchase_order_id is not None:
self.purchase_order_number = "PO"+str(self.purchase_order_id)
return super(PurchaseOrder, self).save()
It is working fine with single creation but when i try to create bulk of data using locust(Testing tool) its giving an error duplicate entry for PurchseOrdernumber Can we modify field value in models itself some thing like this
purchase_order_number = models.CharField(unique=True,default=("PO"+self.purchase_order_id )
To be honest, I don't think it should work when you create multiple instances. Because as I can see from the code:
if self.purchase_order_id is not None:
self.purchase_order_number = "PO"+str(self.purchase_order_id)
Here purchase_order_id will be None when you are creating new instance. Also, until you call super(PurchaseOrder, self).save(), it will not generate purchase_order_id, meaning purchase_order_number will be empty.
So, what I would recommend is to not store this information in DB. Its basically the same as purchase_order_id with PO in front of it. Instead you can use a property method to get the same value. Like this:
class PurchaseOrder(models.Model):
purchase_order_id = models.AutoField(primary_key=True)
# need to remove `purchase_order_number = models.CharField(unique=True)`
...
#property
def purchase_order_number(self):
return "PO{}".format(self.purchase_order_id)
So, you can also see the purchase_order_number like this:
p = PurchaseOrder.objects.first()
p.purchase_order_number
Downside of this solution is that, you can't make any query on the property field. But I don't think it would be necessary anyway, because you can do the same query for the purchase_order_id, ie PurchaseOrder.objects.filter(purchase_order_id=1).

Mongoengine : How to update specific fields of an existing document?

I have an existing mongo document which has been exposed over a REST API. The API request will contain certain fields from the document which either needs to be updated with new values or insert new values in them if the field is null. How to perform the update on fields of an existing mongoengine document? I'm using marshmallow-mongoengine for serialization on flask.
The problem that I'm facing is that if a certain field is missing in the request payload, on calling update with the remaining fields as kwargs leads to setting the missing fields as None. How can update or insert only the fields given in the payload?
Joseph's answer is OK. But another answer wont hurt eh!
Here's how i updated my document using flask-mongoengine
Actual code :
Game.objects(id = _id).update(
set__kickoff = request_json.get('kickoff'),
set__gameid = request_json.get('gameid'),
set__home_team = request_json.get('home_team'),
set__away_team = request_json.get('away_team'),
set__home_win = request_json.get('home_win'),
set__draw = request_json.get('draw'),
set__away_win = request_json.get('away_win'),
set__sport = request_json.get('sport')
)
Game class :
import datetime
flask_mongoengine import BaseQuerySet, MongoEngine
db = MongoEngine()
class Game(db.Document):
kickoff = db.DateTimeField(required=True)
added_on = db.DateTimeField(default=datetime.datetime.utcnow)
gameid = db.FloatField(required=True)
home_team = db.StringField(required=True)
home_win = db.FloatField(required=True)
draw = db.FloatField(required=True)
away_win = db.FloatField(required=True)
away_team = db.StringField(required=True)
sport = db.StringField(required=True)
meta = {
'collection':'games',
'queryset_class': BaseQuerySet
}
PS : Remember to indent the code in python
Additionally I noticed you tagged Marshmallow in your question. Here, a sample derived from their official git repo here
First we need a Mongoengine Document:
import mongoengine as me
class Task(me.EmbeddedDocument):
content = me.StringField(required=True)
priority = me.IntField(default=1)
class User(me.Document):
name = me.StringField()
password = me.StringField(required=True)
email = me.StringField()
tasks = me.ListField(me.EmbeddedDocumentField(Task))
Great ! Now it's time for the Marshmallow Schema. To keep things DRY, we use marshmallow-mongoengine to do the mapping:
import marshmallow_mongoengine as ma
class UserSchema(ma.ModelSchema):
class Meta:
model = User
Finally it's time to use our schema to load/dump documents:First let's create a document
user_schema = UserSchema()
u, errors = user_schema.load({"name": "John Doe", "email":
"jdoe#example.com", "password": "123456","tasks": [{"content": "Find a
proper password"}]})
u.save()
If the document already exists, we can update it using update
u
u2, errors = user_schema.update(u, {"name": "Jacques Faite"})
>>> u2.name
"Jacques Faite"
If you only want to update one single document you can use the save method. That's what I do. If a document already exists, it updates fields instead of creating a new document.
car = Car.objects(pk=car_id) # return a queryset
if car:
car = car.get(pk=car_id) # return an object from queryset
car.make = requestData['make']
car.model = requestData['model']
car.mileage = requestData['mileage']
car.save()
If you want to update many documents then, I recommend checking out the atomic updates section of the user guide.
Something like~
Car.objects(param="param to filter by").update(set__param=newParam)
"set" followed by two underscores is a modifier. There are more modifiers available in the guide I linked above.

Cannot resolve added property of model in views

In my views.py file, I filter objects from a model, and I add some properties to the objects to use them later in templates.
matches = Match.objects.filter(season=season_name).order_by("match_date")
team_list = Team.objects.filter(id__in=team_ids)
for team in team_list:
home_matches = matches.filter(home_team=team)
away_matches = matches.filter(away_team=team)
team.sf = len(Shot.objects.filter(match__in=matches, team=team))
team.sa = len(Shot.objects.filter(match__in=matches, opponent_team=team))
team.pdo = ((team.f / team.sf) + (1 - (team.a / team.sa))) * 1000
team.xpdo = ((team.xgf / team.sf) + (1 - (team.xga / team.sa))) * 1000
For example, in my team model, fields sf, sa, pdo and xpdo does not exist. I calculate those fields on views and use them in a table in my template. There is no problem until here, actually. What I am trying to do is dumping query set as JSON and passing it the template to use in JavaScript.
context["teams_json"] = json.dumps(list(team_list.values_list(
"team_name", "pdo", "xpdo")), cls=DjangoJSONEncoder)
When I run the server, I get the following error:
FieldError at /leagues/turkey2017/
Cannot resolve keyword 'pdo' into field. Choices are: away_team, home_team, id, opponent_team, passmaplineup, passmappass, player_stats_opponent_team, player_stats_team, shooter_team, team_dark_color, team_light_color, team_name
I see that choices are combination of original fields in my Team model and ForeignKey fields in other models such as this field in Shot model:
opponent_team = models.ForeignKey(
Team, related_name="opponent_team", on_delete=models.CASCADE)
How can I use the fields added in views later on in views again?
The problem is that you are trying to use values_list on something that is not a field. I suppose that the reason you are doing so is to remove unnecessary fields from your serialized data. But really using values_list at all here is overkill; you just have three bits of data, you could just as easily dump them manually:
data = [{'pdo': team.pdo, 'xpdo': team.xpdo, 'team_name': team.team_name} for team in team_list]
context["teams_json"] = json.dumps(data)

Django validate data when updating model with primary key

I am having trouble with updating fields of a model instance. The model is as follows:
class commonInfo(models.Model):
mothers_id = models.IntegerField(primary_key=True)
date = models.DateField()
data_collector = models.CharField(max_length=50)
Essentially, I just want to do this, but it won't work because commonInfo has a user defined primary key
commonInfo_form(request.POST or None).is_valid()
Since I am updating, I am overriding date and data_collector, but not mothers_id. So I would want to do something like this, but this specific code is not working
obj = commonInfo.objects.get(pk=commonInfo_id)
form = commonInfo_form(request.POST)
date = form.cleaned_data['data_collector'] #this line is not working
data_collector = form.cleaned_data['data_collector'] #this line is not working
obj.update(**{'date':date, 'data_collector':data_collector})
any ideas? I feel like it is just those two lines that I need to fix. Or if there is a more pythonic way or built method in Django?
Just validate with isinstance. so like,
if isinstance(request.POST['date'], datetime.date) and isinstance(request.POST['data_collector'], str):
# you might have to use getattr for request.POST here, I'm not sure
# and request.POST['date'] would have to be converted from a string to datetime.date I think
date = request.POST['date']
data_collector = request.POST['data_collector']
obj.update(**{'date':date, 'data_collector':data_collector})
The process for adding a record from a form is different from updating an existing instance. All you need to do differently is indicate which instance to bind the form to when you create it, ex:
obj = commonInfo.objects.get(pk=commonInfo_id)
form = commonInfo_form(request.POST, instance=obj)

How to filter with manytomany field?

I have model":
class MyModel(models.Model):
field1 = ...
sites = models.ManyToManyField(Site, blank = True, null=True)
and i want to filter (site is a correct Site object):
qs = MyModel.objects.filter(field1=thing, sites__id=site.id)
but this doesn't work. I get all objects, even those who do not have an entry in the table.
or i tried:
qs = MyModel.objects.filter(field1=thing, sites__in=site)
but i get nothing. Ho to do it?
If i understand your question right you have a specific site and your trying to filter by that site. Then you should filter like this:
site = Site.objects.get(pk=1)
mymodel_for_site = MyModel.objects.filter(field1=thing, sites=site)
This should get all the MyModel instances for a particular site
Try to make it via MyModel object, i.e.:
object = MyModel.objects.get(field1=thing)
qs = object.sites.all()
Check django docs