Deleting Session Variables Django - python

So I have a session variable that has a rough structure like this:
request.session['selected_courses'] = {
'2': {'num_spots_available': 3,
attendees = [ {'first_name': 'Jon', 'last_name': 'Kan'}, ... ]}
...
}
Each key under 'selected_courses' is a course id.
I need to remove an attendee i.e {'first_name': 'Jon', 'last_name': 'Kan'} from a selected course. When I try to do this, the session does not actually delete the attendee. As I try to delete another attendee, the previous attendee pops right back into the session even though my code deleted it before! However, after rerunning this code, it finally deletes the attendee from session.
My code in views.py (i pull data out of POST because I am doing an AJAX request and know the data is not inputted by the user):
course_id = str(request.POST['course_id'])
first_name = str(request.POST['first_name'])
last_name = str(request.POST['last_name'])
request.session['selected_courses'][str(course_id)]['attendees'] = [a for a in request.session['selected_courses'][str(course_id)]['attendees']
if a['first_name'] != first_name or a['last_name'] != last_name]
request.session.modified =True
So I have tried the request.session.modified attribute (as shown above) along with the SESSION_SAVE_EVERY_REQUEST = True and neither worked. (Please note: I am still quite new to Django).

This code is much too complex, and has at least one serious bug. remove does not return the modified list, but None, so if you do attendees = attendees.remove(...) then the attendees will now be None.
A very much simpler way to write this code will be with loops:
for course in request.session['selected_courses']:
if course['course_id'] == course_id:
course['attendees'] = [
a for a in course['attendees']
if a['first_name'] != first_name and a['last_name'] != last_name
]
break
Note, this is not any less efficient, since your calls to map and remove are really loops themselves.
Alternatively, you might consider a different data structure; if you regularly need to search selected_courses for a particular course ID, it would be better to store it as a dict keyed by that ID, rather than a list of dicts containing the ID as a value.
request.session['selected_courses'] = {
'2': [ {'first_name': 'Jon', 'last_name': 'Kan'}, ... ]
}

Related

Get Related Data from ManyToManyField in Django

Working with ManyToManyField I want to get data of all the users related to all the queried model object along with other field data in the model.
For example for the below model, I have 2 users related to this "ChatRoom"
class ChatRoomParticipants(models.Model):
user = models.ManyToManyField(User, related_name='chatroom_users')
room = models.ForeignKey(ChatRoom, on_delete=models.PROTECT)
With the below query
chatrooms = list(ChatRoomParticipants.objects.filter(user=user).values('user__user_uid', 'room__id', 'room__name'))
I'm able to fetch
[{'user__user_uid': UUID('f4253fbd-90d1-471f-b541-80813b51d610'), 'room__id': 4, 'room__name': 'f4253fbd-90d1-471f-b541-80813b51d610-872952bb-6c34-4e50-b6fd-7053dfa583de'}]
But I'm expecting something like
[{
'user__user_uid1': UUID('f4253fbd-90d1-471f-b541-80813b51d610'),
'user__user_uid2': UUID('872952bb-6c34-4e50-b6fd-7053dfa583de'),
'room__id': 4,
'room__name': 'f4253fbd-90d1-471f-b541-80813b51d610-872952bb-6c34-4e50-b6fd-7053dfa583de'
},
{
'user__user_uid1': UUID('f4253fbd-90d1-471f-b541-80813b51d610'),
'user__user_uid2': UUID('eecd66e7-4874-4b96-bde0-7dd37d0b83b3'),
'room__id': 5,
'room__name': 'f4253fbd-90d1-471f-b541-80813b51d610-eecd66e7-4874-4b96-bde0-7dd37d0b83b3'
},
{
'user__user_uid1': UUID('f4253fbd-90d1-471f-b541-80813b51d610'),
'user__user_uid2': UUID('4f4c0f3d-2292-4d06-afdc-1e95962ac5e6'),
'room__id': 6,
'room__name': 'f4253fbd-90d1-471f-b541-80813b51d610-4f4c0f3d-2292-4d06-afdc-1e95962ac5e6'
}]
I've searched and found I can do something like
user_data = chatrooms.users.all().values('user_uid')
But the above doesn't work well with filter and I would miss out data on room.
Note: I know that's not a correct method to do what I'm trying to achieve, if anyone can enlighten with what's the correct way to achieve the same data.
your example is somewhat confusing, but I think what you are looking for is to find the information of the users related to the same room.
chat_room = ChatRoomParticipants.objects.get(id=id_room)
users_chat = chat_room.user.all().values_list('user_uid', flat=True)
data = {
"room__id": chat_room.room.id
"room__name": chat_room.room.name
"users" : users_chat
}
for something more consistent you can use serializers

Filter elements by optional lists of related elements

I have a feeling that I've made things more complex than they need to be - this can't possibly be such a rare case. It seems to me that it should be possible - or perhaps that I'm doing something fundamentally wrong.
The issue at hand is this: I've declared a database element, Element, which consists of about 10 many-to-many relations with other elements, one of which is Tag.
I want to enable the user of my application to filter Element by all of these relations, some of them or none of them. Say the user wants to see only Elements which are related to a certain Tag.
To make things even more difficult, the function that will carry out this objective is called from a graphql API, meaning it will recieve ID's instead of ORM objects.
I'm trying to build a resolver in my Python Flask project, using SQLAlchemy, which will provide an interface like so:
# graphql request
query getElements {
getElements(tags:[2, 3] people:[8, 13]) {
id
}
}
# graphql response
{
"data": {
"getElements": [
{
"id": "2"
},
{
"id": "3"
},
{
"id": "8"
}
]
}
}
I imagine the resolver would look something like this simplified pseudo-code, but I can't for the life of me figure out how to pull it off:
def get_elements(tags=None, people=None):
args = {'tags' : tags, 'people' : people}
if any(args):
data_elements = DataElement.query.filter_by(this in args) # this is the tricky bit - for each of DataElements related elements, I want to check if its ID is given in the corresponding argument
else:
data_elements = DataElement.query.all()
return data_elements
Here's a peek at the simplified database model, as requested. DataElement holds a lot of relations like this, and it works perfectly:
class DataElement(db.Model):
__tablename__ = 'DataElement'
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=DataElementTag, back_populates='data_elements')
class Tag(db.Model):
__tablename__ = 'Tag'
id = db.Column(db.Integer, primary_key=True)
data_elements = db.relationship('DataElement', secondary=DataElementTag, back_populates='tags')
DataElementTag = db.Table('DataElementTag',
db.Column('id', db.Integer, primary_key=True),
db.Column('data_element_id', db.Integer, db.ForeignKey('DataElement.id')),
db.Column('tag_id', db.Integer, db.ForeignKey('Tag.id'))
)
Please, ORM wizards and python freaks, I call upon thee!
I've solved it in a rather clunky manner. I suppose there must be a more elegant way to pull this off, and am still holding out for better answers.
I ended up looping over all the given arguments and using eval() (not on user input, don't worry) to get the corresponding database model. From there, I was able to grab the DataElement object with the many-to-many relationship. My final solutions looks like this:
args = {
'status' : status,
'person' : people,
'tag' : tags,
'event' : events,
'location' : locations,
'group' : groups,
'year' : year
} # dictionary for args for easier data handling
if any(args.values()):
final = [] # will contain elements matching criteria
for key, value in args.items():
if value:
model = eval(key.capitalize()) # get ORM model from dictionary key name (eval used on hardcoded string, hence safe)
for id in value:
filter_element = model.query.filter_by(id=id).one_or_none() # get the element in question from db
if filter_element:
elements = filter_element.data_elements # get data_elements linked to element in question
for element in elements:
if not element in final: # to avoid duplicates
final.append(element)
return final

Dynamically pass arguments to objects.filter

I am pretty new to Django and I am trying to get a query set from a filter function. This filter function is supposed to be able to take 1 to 5 arguments and I am not sure how to handle that.
I have not found anything here that might help me, so if you do know of some other question that might help please let me know.
views.py:
#api_view(('Get',))
def update(request, REQUEST):
if request.method == "Get":
requestlist = REQUEST.split('&')
for keys in requestlist:
if 'module' in keys:
module = keys[8:]
if 'value' in keys:
value = keys[6:]
if 'user' in keys:
user= keys[5:]
if 'time1' in keys:
time1 = keys[6:]
if 'time2' in keys:
time2 = keys[6:]
item = Post.objects.filter(name=Name, user=USER, ...)
The full request string will look like name=NAME&value=VALUE&user=USER&time1=FIRSTTIME&time2=SECONDTIME but it could also be any combination of the individual variables like name&time1.
Now I want to be able to do that with one filter method instead of creating like 2^5 for each different szenario.
The full request string will look like name=NAME&value=VALUE&user=USER&time1=FIRSTTIME&time2=SECONDTIME.
This is a query string [wiki], and Django automatically parses this to a dictionary-like QueryDict, you thus should not specify this yourself. You can work with:
if request.method == 'GET':
Post.objects.filter(**request.GET.dict())
I would however advise to only allow specific keys, and thus not all keys, since then the database is less secure: one can use the filtering mechanism to retrieve data.
It thus might be better to work with:
datas = {}
accept_keys = {'module', 'value', 'user', 'time1', 'time2'}
for key, value in request.GET.dict().items():
if key in accept_keys:
datas[key] = value
if request.method == 'GET':
Post.objects.filter(**datas)
In that case the item after the path is the query string, and the separator between the path and the query string is a question mark (?).
The path thus looks like:
urlpatterns = [
# …,
path('some/path/', views.update, name='update'),
# …
]
and you thus query the path with some.host.com/some/path?name=NAME&value=VALUE&user=USER&time1=FIRSTTIME&time2=SECONDTIME.

Django Chartit can't read #property attributes in model.Models

anyone know how to reference a field value in a model when it's described with the 'property' decorator?
I have an 'order' model with a property decorator which totals a number of values in fields related to my 'order' class via a foreign key.
#property
def total_price(self):
"""
The total value of all items in the order, minus any discounts.
"""
total = sum([item.total_price
for item in self.order_orderitem_set.all()])
discounts = sum([item.discount
for item in self.order_orderitem_set.all()])
return total - discountsenter code here
When I reference this type it's quite simple. I do:
myOrders = Orders.objects.all()
for key in myOrders:
print "My total is: ", key.total_price
However if I use the source attribute as: Orders.objects.all and try and reference this value 'total_orders' Chartit provides me with an error that it can't find this field value.
My chartit datapool looks like:
orderdata = \
DataPool(
series=
[{'options': {
'source': Order.objects.all()},
'terms': [
'order_date',
'total_price']}
])
#Step 2: Create the Chart object
cht = Chart(
datasource = orderdata,
series_options =
[{'options':{
'type': 'line',
'stacking': False},
'terms':{
'order_date': [
'total_price']
}}],
chart_options =
{'title': {
'text': 'Total Orders Over Time'},
'xAxis': {
'title': {
'text': 'Order Date'}}})
I get the error:
Field u'total_price' does not exist. Valid lookups are promo_code, enduser_address, etc....
It looks like to me it is not able to reference my 'property' within the model. Is this just a limitation of the framework?
Does anyone know of a neat way of getting round this - it seems my options are:
1) Create my own json object and iterate around my 'orders' and create my own data list. Then pass this to highcharts directly; or
2) Create another table say 'OrderSaleHistory' and populate for each month via a management function that django will update periodically or from manual action. This new table will then be passed to chartit.
Or does anyone have better ideas? :-)
This is my first 'post' so quite a newbie in posting but not reading!!!!
Kind regards, Nicholas.

How do I look get an associated value in a json variable using python?

How do I look up the 'id' associated with the a person's 'name' when the 2 are in a dictionary?
user = 'PersonA'
id = ? #How do I retrieve the 'id' from the user_stream json variable?
json, stored in a variable named "user_stream"
[
{
'name': 'PersonA',
'id': '135963'
},
{
'name': 'PersonB',
'id': '152265'
},
]
You'll have to decode the JSON structure and loop through all the dictionaries until you find a match:
for person in json.loads(user_stream):
if person['name'] == user:
id = person['id']
break
else:
# The else branch is only ever reached if no match was found
raise ValueError('No such person')
If you need to make multiple lookups, you probably want to transform this structure to a dict to ease lookups:
name_to_id = {p['name']: p['id'] for p in json.loads(user_stream)}
then look up the id directly:
id = name_to_id.get(name) # if name is not found, id will be None
The above example assumes that names are unique, if they are not, use:
from collections import defaultdict
name_to_id = defaultdict(list)
for person in json.loads(user_stream):
name_to_id[person['name']).append(person['id'])
# lookup
ids = name_to_id.get(name, []) # list of ids, defaults to empty
This is as always a trade-off, you trade memory for speed.
Martijn Pieters's solution is correct, but if you intend to make many such look-ups it's better to load the json and iterate over it just once, and not for every look-up.
name_id = {}
for person in json.loads(user_stream):
name = person['name']
id = person['id']
name_id[name] = id
user = 'PersonA'
print name_id[user]
persons = json.loads(...)
results = filter(lambda p:p['name'] == 'avi',persons)
if results:
id = results[0]["id"]
results can be more than 1 of course..

Categories

Resources