The context within the first conditional statement is delivered well, but the context updated within the second conditional statement is not delivered in HTML.
For example, 'MODEL_LIST' in first context is delivered well, but 'mape_val' in second context is not. I want it to be delivered.
How Can I solve this problem ?
<views.py function CODE>
def csv_forecast(request):
context = {}
username = request.user
if request.method == 'POST' and request.FILES.get('csvfile'):
uploaded_file = request.FILES.get('csvfile')
p_data = pd.read_csv(uploaded_file)
p_data.reset_index(drop=True, inplace=True)
columns_list = list(p_data.columns)
columns_list = [column.lower() for column in columns_list]
p_data.columns = columns_list
os.makedirs('media/csv', exist_ok=True)
p_data.to_csv(f'media/csv/{username}.csv', index=False)
start_date = p_data.loc[0, 'date']
len_date = int(len(p_data)*0.8)
end_date = p_data.loc[len_date, 'date']
datas = []
for i in range(1, len(columns_list)):
datas.append(columns_list[i])
MODEL_LIST = ['ARIMA', 'EMA5', 'LSTM']
context = {'datas' : datas, 'd' : p_data, 'columns_list' : columns_list, 'MODEL_LIST' : MODEL_LIST,
'start_date' : start_date, 'end_date' : end_date}
if request.POST.get('sendModel') and request.POST.get('sendPdata') and request.POST.get('sendRdata'):
send_pdata = request.POST.get('sendPdata')
send_rdata = request.POST.get('sendRdata')
send_model = request.POST.get('sendModel')
cleaned_pdata = re.split(r'[\[\],"]', send_pdata)
cleaned_rdata = re.split(r'[\[\],"]', send_rdata)
cleaned_model = re.split(r'[\[\],"]', send_model)
selected_pdata = [i for i in cleaned_pdata if len(i) >= 1]
selected_rdata = [i for i in cleaned_rdata if len(i) >= 1]
selected_model = [i for i in cleaned_model if len(i) >= 1]
csv_data = pd.read_csv(f'media/csv/{username}.csv')
mape_val, y_pred, y_test, test_date = model_main(csv_data, selected_pdata,selected_rdata, selected_model)
mape_val = float(mape_val)
print(mape_val)
fs = FileSystemStorage(location=f'media/csv/')
fs.delete(f'{username}.csv')
context.update({'mape_val':mape_val, 'y_pred':y_pred, 'y_test':y_test, 'test_date':test_date})
return render(request, 'csv_forecast.html', context)
HTML CODE PICTURE
HTML PAGE PICTURE
Debugging
Debug Console
I am trying to use Python Graphene GraphQL to implement a search endpoint return all products based on name. However, in my database I have three product tables that respectfully contains different product types - Cards, Tokens, Sealed Products.
I want to return the data under a single nest in the Json response. The relay connection I am using is from https://github.com/saltycrane/graphene-relay-pagination-example/blob/artsy-example/README.md.
Something along the lines of:
Code:
import graphene
from django.db.models import Q
from graphene import relay, ObjectType
from graphene_django import DjangoObjectType
from magic.models import magic_sets_cards, magic_sets_tokens
from magic.pagination.fields import ArtsyConnection, ArtsyConnectionField
class MagicCards(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
mana_cost_list = graphene.List(graphene.String)
class Meta:
model = magic_sets_cards
interfaces = (relay.Node,)
filter_fields = {'name': ['icontains']}
connection_class = ArtsyConnection
class MagicTokens(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
class Meta:
model = magic_sets_tokens
interfaces = (relay.Node,)
filter_fields = {'name': ['icontains']}
connection_class = ArtsyConnection
class SearchQuery(ObjectType):
magic_cards = ArtsyConnectionField(MagicCards)
magic_tokens = ArtsyConnectionField(MagicTokens)
# pseudo code:
all_products = combine(magic_cards, magic_tokens)
#staticmethod
def resolve_all_products(self, info, **kwargs):
return
#staticmethod
def resolve_magic_cards(self, info, **kwargs):
sql_number_to_int = "CAST((REGEXP_MATCH(number, '\d+'))[1] as INTEGER)"
excluded_sides = ['b', 'c', 'd', 'e']
return magic_sets_cards.objects.exclude(side__in=excluded_sides).extra(select={'int': sql_number_to_int}).order_by('-set_id__release_date', 'set_id__name', 'int', 'number').all()
#staticmethod
def resolve_magic_tokens(self, info, **kwargs):
sql_number_to_int = "CAST((REGEXP_MATCH(number, '\d+'))[1] as INTEGER)"
excluded_sides = ['b', 'c', 'd', 'e']
return magic_sets_tokens.objects.exclude(side__in=excluded_sides).extra(select={'int': sql_number_to_int}).order_by('-set_id__release_date', 'set_id__name', 'int', 'number').all()
searchSchema = graphene.Schema(query=SearchQuery)
Query:
{
allProducts(name_Icontains: "Spellbook", first: 12, after: "") {
pageCursors {
previous {
cursor
}
first {
cursor
page
}
around {
cursor
isCurrent
page
}
last {
cursor
page
}
next {
cursor
}
}
edges {
node {
... on MagicCards {
name
}
... on MagicTokens {
name
}
}
}
}
}
Now I could have the following Query, however it would mean that each product type would be under its own nest in the Json response with its own page cursors which I am not looking for.
{
magicCards(name_Icontains: "Spellbook", first: 12, after: "") {
pageCursors {
...
}
edges {
node {
name
}
}
}
magicTokens(name_Icontains: "Spellbook", first: 12, after: "") {
pageCursors {
...
}
edges {
node {
name
}
}
}
}
EDIT: adding code for ArtsyConnection:
fields.py
from graphene import Boolean, Field, Int, List, ObjectType, String
from graphene.relay import Connection
from graphene_django.filter import DjangoFilterConnectionField
from .helpers import convert_connection_args_to_page_options
from .pagination import create_page_cursors
class PageCursor(ObjectType):
cursor = String()
is_current = Boolean()
page = Int()
class PageCursors(ObjectType):
around = List(PageCursor)
first = Field(PageCursor)
last = Field(PageCursor)
next = Field(PageCursor)
previous = Field(PageCursor)
class ArtsyConnection(Connection):
class Meta:
abstract = True
page_cursors = Field(PageCursors)
class ArtsyConnectionField(DjangoFilterConnectionField):
#classmethod
def resolve_connection(cls, _connection, args, iterable, max_limit=None):
connection = super(ArtsyConnectionField, cls).resolve_connection(
_connection, args, iterable, max_limit
)
page_options = convert_connection_args_to_page_options(args)
page_cursors = create_page_cursors(page_options, connection.length)
connection.page_cursors = page_cursors
return connection
helpers.py
from graphql_relay import from_global_id
def convert_connection_args_to_page_options(connection_args):
paging_params = get_paging_parameters(connection_args)
size = paging_params.get("limit")
offset = paging_params.get("offset")
page = round((size + offset) / size) if size else 1
return {"page": page, "size": size}
def get_paging_parameters(args):
[is_forward_paging, is_backward_paging] = check_paging_sanity(args)
first = args.get("first")
last = args.get("last")
after = args.get("after")
before = args.get("before")
def get_id(cursor):
_, _id = from_global_id(cursor)
return int(_id)
def next_id(cursor):
return get_id(cursor) + 1
if is_forward_paging:
return {"limit": first, "offset": next_id(after) if after else 0}
elif is_backward_paging:
limit = last
offset = get_id(before) - last
if offset < 0:
limit = max(last + offset, 0)
offset = 0
return {"limit": limit, "offset": offset}
else:
return {}
def check_paging_sanity(args):
first = args.get("first")
last = args.get("last")
after = args.get("after")
before = args.get("before")
is_forward_paging = bool(first) or bool(after)
is_backward_paging = bool(last) or bool(before)
if is_forward_paging and is_backward_paging:
raise Exception("cursor-based pagination cannot be forwards AND backwards")
if is_forward_paging and before or is_backward_paging and after:
raise Exception("paging must use either first/after or last/before")
if is_forward_paging and first < 0 or is_backward_paging and last < 0:
raise Exception("paging limit must be positive")
if last and not before:
raise Exception("when paging backwards, a 'before' argument is required")
return [is_forward_paging, is_backward_paging]
pagination.py
import math
from graphql_relay import to_global_id
PREFIX = "arrayconnection"
PAGE_NUMBER_CAP = 100
def page_to_cursor(page, size):
return to_global_id(PREFIX, (page - 1) * size - 1)
def page_cursors_to_array(start, end, current_page, size):
cursors = []
for page in range(start, end + 1):
cursors.append(page_to_cursor_object(page, current_page, size))
return cursors
def page_to_cursor_object(page, current_page, size):
return {
"cursor": page_to_cursor(page, size),
"page": page,
"is_current": current_page == page,
}
def compute_total_pages(total_records, size):
return min(math.ceil(total_records / size), PAGE_NUMBER_CAP)
def create_page_cursors(page_options, total_records, max_pages=5):
current_page = page_options["page"]
size = page_options["size"]
if max_pages % 2 == 0:
print(f"Max of {max_pages} passed to page cursors, using {max_pages + 1}")
max_pages = max_pages + 1
total_pages = compute_total_pages(total_records, size)
if total_pages == 0:
page_cursors = {"around": [page_to_cursor_object(1, 1, size)]}
elif total_pages <= max_pages:
page_cursors = {
"around": page_cursors_to_array(1, total_pages, current_page, size)
}
elif current_page <= math.floor(max_pages / 2) + 1:
page_cursors = {
"last": page_to_cursor_object(total_pages, current_page, size),
"around": page_cursors_to_array(1, max_pages - 1, current_page, size),
}
elif current_page >= total_pages - math.floor(max_pages / 2):
page_cursors = {
"first": page_to_cursor_object(1, current_page, size),
"around": page_cursors_to_array(
total_pages - max_pages + 2, total_pages, current_page, size
),
}
else:
offset = math.floor((max_pages - 3) / 2)
page_cursors = {
"first": page_to_cursor_object(1, current_page, size),
"around": page_cursors_to_array(
current_page - offset, current_page + offset, current_page, size
),
"last": page_to_cursor_object(total_pages, current_page, size),
}
if current_page > 1 and total_pages > 1:
page_cursors["previous"] = page_to_cursor_object(
current_page - 1, current_page, size
)
if current_page < total_pages and total_pages > 1:
page_cursors["next"] = page_to_cursor_object(
current_page + 1, current_page, size
)
return page_cursors
You need to use Union type. Try this:
class MagicCards(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
mana_cost_list = graphene.List(graphene.String)
class Meta:
model = magic_sets_cards
interfaces = (relay.Node,)
class MagicTokens(DjangoObjectType):
id = graphene.ID(source='pk', required=True)
class Meta:
model = magic_sets_tokens
interfaces = (relay.Node,)
class SearchType(graphene.Union):
class Meta:
types = (MagicCards, MagicTokens)
class SearchConnection(graphene.Connection):
class Meta:
node = SearchType
class SearchQuery(ObjectType):
all_products = graphene.ConnectionField(SearchConnection, name__icontains=String())
#staticmethod
def resolve_all_products(self, info, **kwargs):
# do filtering with kwargs['name__icontains']
sql_number_to_int = "CAST((REGEXP_MATCH(number, '\d+'))[1] as INTEGER)"
excluded_sides = ['b', 'c', 'd', 'e']
items = list( magic_sets_cards.objects.exclude(side__in=excluded_sides).extra(select={'int': sql_number_to_int}).order_by('-set_id__release_date', 'set_id__name', 'int', 'number').all())
items.extend(magic_sets_tokens.objects.exclude(side__in=excluded_sides).extra(select={'int': sql_number_to_int}).order_by('-set_id__release_date', 'set_id__name', 'int', 'number').all())
return items
searchSchema = graphene.Schema(query=SearchQuery)
You have to avoid DjangoConnectionField or DjangoFilterConnectionField since they don't accept Union types. The filtering logic has to be implemented in the login, which you can easily do with django-filter. The pageInfo object returned will be the default startCursor, endCursor, hasNextPage, hasPreviousPage. I'll need to see your ArtsyConnection class to customize it.
https://docs.graphene-python.org/en/latest/types/unions/
Edit
You need to subclass ConnectionField instead of DjangoConnectionField in your ArtsyConnectionField. The rest should just work. The downside is that you have to implement filtering, sorting and pagination yourself, all of which DjangoFilterConnectionField would do for you. There is no deterministic way to paginate and filter two models using the connection parameters. You need to do this according to your use case. For example, let's say you return 20 results per search. How many, of those should be MagicCards and how many MagicTokens. Or, should the results return MagicCards first and then MagicTokens. What about when you send a cursor(page). What does the cursor denote? Is the offset based on MagicCards or MagicTokens. Or is it on the combined result of them both. So, for each search, you need to filter on the MagicTokens and MagicCards, then combine them, and then apply pagination on them. You cannot achieve this using DjangoFilterConnectionField. You'll have to write your own logic for that.
I have a function that makes a queryset when data from my frontend is posted.
This viewset is using a serializer of combined models.
On my index page on the fronted I have a treeview filter and this view loads the query to
a config page. I need to access the event id's after this query is made to be passed to a separate task on the backend for polling.
However I cannot access the data in this function. How would I get retrieve this query and filter on the data? right now I can't print the queryset to see its structure.
Edit:
I can see the response payload now and the structure is as follows
[{"id":395,"event":{"id":175,"start_time":"28-10-20","sport_id":"9","event_id":"1576232279920003","event_name":"Botic Van de Zandschulp vs Benjamin Bonzi","status":"open"},"market":{"id":198,"market_id":"1576232286670003","market_name":"Moneyline","status":"open","volume":50.4951,"is_ip":"False","event":175},"bettriggers":null,"stakes":null,"userstakes":null,"order":null,"runner_id":"1576232286740003","name":"Botic Van de Zandschulp","back_odds":1.62893,"lay_odds":1.68028},{"id":396,"event":{"id":175,"start_time":"28-10-20","sport_id":"9","event_id":"1576232279920003","event_name":"Botic Van de Zandschulp vs Benjamin Bonzi","status":"open"},"market":{"id":198,"market_id":"1576232286670003","market_name":"Moneyline","status":"open","volume":50.4951,"is_ip":"False","event":175},"bettriggers":null,"stakes":null,"userstakes":null,"order":null,"runner_id":"1576232286780103","name":"Benjamin Bonzi","back_odds":2.47,"lay_odds":2.59}]
class CombinedViewSet(mixins.ListModelMixin,
mixins.DestroyModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
permission_classes = [IsMeOrReadOnly]
queryset = Runner.objects.all()
serializer_class = CombinedSerializer
#action(detail=False, methods=['POST','GET])
def loaditem(self, request):
keys = request.data['keys']
queryset = []
for xx in keys:
if xx['time_key'] is None:
if xx['event_key'] is None:
queryset.extend(Runner.objects.filter(event__sport_id=xx['sport_key']))
else:
queryset.extend(Runner.objects.filter(event__event_id=xx['event_key']))
else:
date_str = xx['time_key']
datetime_obj = datetime.datetime.strptime(date_str, '%d-%m-%y')
queryset.extend(Runner.objects.filter(event__start_time__date=datetime_obj, event__sport_id=xx['sport_key']))
serializer_class = CombinedSerializer(queryset, many=True)
return Response(serializer_class.data)
What my end goal is to pass in the filtered list of event_id's from load item function to a backend celery task
#shared_task(bind=True, base=QueueOnce, once={'graceful': True})
def get_events(self):
api = get_client()
sports = api.reference_data.get_sports()
logger.warning(f'GET EVENTS task has been called now')
events = api.market_data.get_selected_events(event_ids=['2323','34343','1576232279920003','etc'])
This is what my serializer looks like
class CombinedSerializer(serializers.ModelSerializer):
event = EventSerializer()
market = MarketSerializer()
bettriggers = BetTriggersSerializer()
stakes = StakesSerializer()
userstakes = UserStakesSerializer()
order = OrderStakesSerializer()
class Meta:
model = Runner
fields= '__all__'
Frontend code for posting data
load_item: function (event) {
if(this.value == null) return;
var len = this.value.length;
var req_key = [];
for (var x=0; x<len; x++) {
var str = ''+this.value[x];
var tmp_arr = str.split('#');
var sport_key = null;
var time_key = null;
var event_key = null;
switch(tmp_arr.length) {
case 1:
sport_key = tmp_arr[0];
break;
case 2:
event_key = tmp_arr[1];
break;
case 3:
time_key = tmp_arr[2];
sport_key = tmp_arr[1];
break;
}
req_key.push({sport_key:sport_key, event_key:event_key, time_key:time_key});
}
var vobj = this
this.$axios.post('/api/combined/loaditem/', {
keys : req_key
})
.then(function (response) {
vobj.$store.dispatch('load_runner', response.data)
vobj.$router.push('/configuration')
})
.catch(function (error) {
//currentObj.output = error;
console.log(error)
});
},
This is the error I get when I try to load my indexes.html page:
MissingSchema at /indexes/
Invalid URL "<_io.TextIOWrapper name='tableInfo.json' mode='r' encoding='cp1252'>": No schema supplied. Perhaps you meant
http://<_io.TextIOWrapper name='tableInfo.json' mode='r'
encoding='cp1252'>?
I am not sure why this is happening, I am trying to read from a local JSON file and display it in a table
This is my views.py code:
def indexes(request):
with open('tableInfo.json') as json_file:
if request.POST:
form = Sea(request.POST)
po = request.POST.get('poNo')
dc = request.POST.get('dcNo')
vendor = request.POST.get('vendor')
order_date = request.POST.get('order_date')
delivery_date = request.POST.get('delivery_date')
payload = {}
if len(po) > 8:
payload['poNo'] = po
if "DC" in dc:
payload['dcNo'] = dc
if len(vendor) > 8:
payload['vendorNo'] = vendor
if len(order_date) > 6:
payload['orderDate'] = order_date
if len(delivery_date) > 6:
payload['deliveryDate'] = delivery_date
data = json.loads((requests.get(json_file, payload)).content)
if data['returnCode'] == 0:
resultList = data['resultList']
else:
resultList = []
else:
form = Sea()
resultList = []
context = {
'data': resultList,
'form': form
}
return render(request, 'users/indexes.html', context)
To read from local file you need
data = json.loads( json_file.read() )
or using load() (without "s" at the end)
data = json.load( json_file )
You don't need requests.get() which makes problem.
I'm trying to practice some django basics by implementing my own sortable table in Django and I've run into a couple of snags.
Here's the code that I'm working with in my view:
def __table_view_helper__(request):
if not request.session.__contains__('filters'):
filters = {'filterA':'',
'filterB':'',
'filterC':''}
request.session['filters'] = filters
if not request.session.__contains__('headers'):
headers = {'sortA':'asc',
'sortB':'des',
'sortC':'asc',
'sortD':'asc'}
request.session['headers'] = headers
def table_view(request):
__table_view_helper__(request)
records = Record.objects.all()
nums = list(set(records.values_list('fieldA','fieldA')))
nums.sort()
if request.method == 'POST':
filter = FilterForm(nums,request.POST)
if filter.is_valid():
fieldA = filter.cleaned_data['fieldA']
fieldB = filter.cleaned_data['fieldB']
fieldC = filter.cleaned_data['fieldC']
filters = request.session['filters']
filters['fieldA'] = fieldA
filters['fieldB'] = fieldB
filters['fieldC'] = fieldC
request.session['filters'] = filters
else:
filter = FilterForm(nums)
filters = request.session['filters']
filter.fields['fieldA'].initial = filters['fieldA']
filter.fields['fieldB'].initial = filters['fieldB']
filter.fields['fieldC'].initial = filters['fieldC']
if filters['fieldA']:
records = records.filter(fieldA=filters['fieldA'])
if filters['fieldB']:
records = records.filter(fieldB__in=filters['fieldB'])
if filters['fieldC']:
records = records.filter(fieldC=filters['fieldC'])
sort = request.GET.get('sort')
if sort is not None:
headers = request.session['headers']
if headers[sort] == "des":
records = records.order_by(sort).reverse()
headers[sort] = "asc"
else:
records = records.order_by(sort)
headers[sort] = "des"
request.session['headers'] = headers
return render_to_response("secure/table.html",{'user':request.user,'profile':request.user.get_profile(),'records':records,'fform':filter})
I changed a lot of my code to use sessions now. It works fine. Is this a good way to do this you think?
To set the initial values from the view you have to do:
filter.fields['fieldA'].initial = filters['filterA']
To keep user related data persistent through different requests you shouldn't use globals, but sessions!