Struggling with many to many field - django

I'm trying to create a new product.
Here is my model :
class Product(models.Model) :
door = models.ForeignKey(Door, on_delete=models.CASCADE)
options = models.ManyToManyField(Option)
Here is my views :
def new_product(request, door_id) :
door = get_object_or_404(Door, id=door_id)
checked = request.POST.getlist('checks[]')
c_checked = []
for check in checked :
new_check = get_object_or_404(Option, name=check)
c_checked.append(new_check)
product = Product.objects.create(
door = door,
options = c_checked,
)
product.save()
return render(request, "confirmation.html")
Unfortunately, when I run the server, I get an error saying :
Direct assignment to the forward side of a many-to-many set is
prohibited. Use options.set() instead
Please help me if you have the answer.
.

According to the documentation, you should use add. create method represents one insert in a database but you want to insert multiple records.
def new_product(request, door_id) :
door = get_object_or_404(Door, id=door_id)
checked = request.POST.getlist('checks[]')
c_checked = []
for check in checked :
new_check = get_object_or_404(Option, name=check)
c_checked.append(new_check)
product = Product.objects.create(door=door)
product.options.add(*c_checked)
return render(request, "confirmation.html")

Related

For each item update database

I'm a total beginner with Python/Django and trying to understand why this isn't working. I have a function that contains a for loop, doing some logic and then updating a model. but when I have more than 1 item in the loop I get a UNIQUE constraint failed: app_token.token_name error.
So I think I'm misunderstanding how the loop is working?
function
tokens = Token.objects.all()
for item in tokens:
if item.token_contract_address is not None:
token = Token.objects.get(pk=item.id)
parameters = {
'address':token.token_contract_address
}
session = Session()
session.headers.update(headers)
response = session.get(url, params=parameters)
resp = json.loads(response.text)
token_id = (resp['data'][next(iter(resp['data']))]['id'])
logo = (resp['data'][next(iter(resp['data']))]['logo'])
url = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest'
parameters = {
'id':token_id
}
session = Session()
session.headers.update(headers)
response = session.get(url, params=parameters)
id = str(token_id)
price = (json.loads(response.text)['data'][id]['quote']['USD']['price'])
market_cap = (json.loads(response.text)['data'][id]['quote']['USD']['market_cap'])
change = (json.loads(response.text)['data'][id]['quote']['USD']['percent_change_24h'])
r = Token.objects.update(token_capture_date = formatedDate, token_price = price, token_name=item.token_name )
I'm expecting the this Token.objects.update(token_capture_date = formatedDate, token_price = price, token_name=item.token_name ) to update the model based on the item loop?
The model is very simple:
class Token(models.Model):
token_name = models.CharField(max_length=50, blank=False, unique=True)
token_slug = models.CharField(max_length=50, blank=True,null=True)
token_price = models.FloatField(blank=True,null=True)
token_capture_date = models.DateField(blank=True,null=True)
token_contract_address = models.CharField(max_length=50, blank=True,null=True)
def __str__(self):
return str(self.token_name)
I'm using the update on the objects and have tried removing the token_name, and tried using token.token_name
If I remove token_name= it updates both items in the database with the same values? which makes me think its this line r = Token.objects.update(token_capture_date = formatedDate, token_price = price, token_name=item.token_name ) do i need to apply some kinda of filter?
Thanks
I believe that by calling Token.objects.update() you actually end up trying to update all Token objects. Since token_name has to be unique, and you are giving it the same name as another Token object it throws that error.
Since you are already in a for loop, you can simply update the token that is currently being processed.
My suggestion would be to use this code instead:
item.token_capture_date = formattedDate
item.token_price = price
item.save()
This will make it so that the current token object which is being processed in the for loop has its respective field values updated and saved in the database.
Also, this line is unnecessary: token = Token.objects.get(pk=item.id) as we already have access to the token through the looping variable item.
Do let me know if this helps!

django filter data and make union of all data points to assignt to a new data

My model is as follows
class Drawing(models.Model):
drawingJSONText = models.TextField(null=True)
project = models.CharField(max_length=250)
Sample data saved in drawingJSONText field is as below
{"points":[{"x":109,"y":286,"r":1,"color":"black"},{"x":108,"y":285,"r":1,"color":"black"},{"x":106,"y":282,"r":1,"color":"black"},{"x":103,"y":276,"r":1,"color":"black"},],"lines":[{"x1":109,"y1":286,"x2":108,"y2":285,"strokeWidth":"2","strokeColor":"black"},{"x1":108,"y1":285,"x2":106,"y2":282,"strokeWidth":"2","strokeColor":"black"},{"x1":106,"y1":282,"x2":103,"y2":276,"strokeWidth":"2","strokeColor":"black"}]}
I am trying to write a view file where the data is filtered based on project field and all the resulting queryset of drawingJSONText field are made into one data
def load(request):
""" Function to load the drawing with drawingID if it exists."""
try:
filterdata = Drawing.objects.filter(project=1)
ids = filterdata.values_list('pk', flat=True)
length = len(ids)
print(list[ids])
print(len(list(ids)))
drawingJSONData = dict()
drawingJSONData = {'points': [], 'lines': []}
for val in ids:
if length >= 0:
continue
drawingJSONData1 = json.loads(Drawing.objects.get(id=ids[val]).drawingJSONText)
drawingJSONData["points"] = drawingJSONData1["points"] + drawingJSONData["points"]
drawingJSONData["lines"] = drawingJSONData1["lines"] + drawingJSONData["lines"]
length -= 1
#print(drawingJSONData)
drawingJSONData = json.dumps(drawingJSONData)
context = {
"loadIntoJavascript": True,
"JSONData": drawingJSONData
}
# Editing response headers and returning the same
response = modifiedResponseHeaders(render(request, 'MainCanvas/index.html', context))
return response
I runs without error but it shows a blank screen
i dont think the for function is working
any suggestions on how to rectify
I think you may want
for id_val in ids:
drawingJSONData1 = json.loads(Drawing.objects.get(id=id_val).drawingJSONText)
drawingJSONData["points"] = drawingJSONData1["points"] + drawingJSONData["points"]
drawingJSONData["lines"] = drawingJSONData1["lines"] + drawingJSONData["lines"]

Django Retrive data after a specific number or index

i have two rendered contexts in my view:
def PostHomeView(request):
RecentPost = Post.objects.order_by("-date").all()[:5]
AllOtherPosts = Post.objects.order_by("-date").all()
template_name = 'lista_post.html'
context = {**strong text**
'recentposts' : RecentPost,
'allposts' : AllOtherPosts
}
return render(request,template_name,context)
in the second one ('allposts') i would like to get all objcects without the first fve
how can i do it?
Use slicing as AllOtherPosts = Post.objects.order_by("-date").all()[5:]

Django request with user criteria

I would like to get some help about my future process. I would like that users could create his own django request and then get the result.
Up to now, I created django requests in my script but there are static requests :
request1 = Test.objects.all()
or
query_lastname_ID = request.GET.get('q1ID')
query_firstname_ID = request.GET.get('q1bisID')
query_naissance_ID = request.GET.get('q1terID')
if query_firstname_ID and query_lastname_ID and query_naissance_ID :
query_ID_list = Individu.objects.filter(
Nom__icontains=query_lastname_ID,
Prenom__icontains=query_firstname_ID,
VilleNaissance__icontains=query_naissance_ID)
if len(query_ID_list) != 0 :
messages.success(request, 'Miracle .. Vous avez un résultat !')
else :
messages.error(request, "Oh non .. Vous n'avez aucun résultat !")
All of these requests are static.
Now I would like to let the choice to the user between criteria or mathematic operator.
I won't write table fields in my request but the user could have the choice to get what he wants :
one field
two fields
x fields
the mathematic operator (=, >, <, not egal, ...)
comparison between fields
...
User could get a result thanks to a dynamic request. He could create himself Django request.
Is it possible ? I don't find example or documentations about this kind of process :/
You can try create filter as dict, for example:
map_fields_get = {
'Nom': 'q1ID', 'Prenom': 'q1bisID', 'VilleNaissance': 'q1terID'
}
condition_param = 'YOUR_GET_NAME_FOR_CONDITION'
condition_list = ['icontains', 'iexact', 'gt', 'lt']
condition = request.GET.get('condition_param', 'icontains')
if condition not in condition_list:
# add your logic set default or raise
condition = condition_list[0]
qs_f = {}
for get_f, f in map_fields_get.items():
get_val = request.GET.get(get_f, None)
if get_val:
qs_f_key = '%s__%s' % (f, condition)
qs_f[qs_f_key] = get_val
if qs_f:
query_ID_list = Individu.objects.filter(**qs_f)

Computed Property for Google Datastore

I am not sure exactly how achieve this.
I have a model defined as
class Post(ndb.Model):
author_key = ndb.KeyProperty(kind=Author)
content = ndb.StringProperty(indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True)
title = ndb.StringProperty(indexed=True)
topics = ndb.StructuredProperty(Concept, repeated=True)
concise_topics = ndb.ComputedProperty(get_important_topics())
#classmethod
def get_important_topics(cls):
cls.concise_topics = filter(lambda x: x.occurrence > 2, cls.topics)
return cls.concise_topics
I like to set the value of concise_topics (Which is on the same type as topics) to a subset acheived via get_important_topics method. This should happen the moment the topics property has been set.
How do I define the "concise_topics" property in the Post class ?
With class method, you don't have access to the instance values. And also you shouldn't call the function, only pass it to the computed property, and let it call by itself.
class Post(ndb.Model):
author_key = ndb.KeyProperty(kind=Author)
content = ndb.StringProperty(indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True)
title = ndb.StringProperty(indexed=True)
topics = ndb.StructuredProperty(Concept, repeated=True)
def get_important_topics(self):
return filter(lambda x: x.occurrence > 2, self.topics)
concise_topics = ndb.ComputedProperty(get_important_topics)
As far as I remember the computed property is set on each put call, so your topics should be already there by that time.