I'm creating a quiz project using Django with MongoEngine. Multiple Choice Questions and quiz are two separated apps. I want to fetch multiple choice in quiz based on m_id (unique number for each multiple choice). I'm a beginner and need a little help. How can i achieve thisMCQS Model
from django_mongoengine import Document, EmbeddedDocument, fields
class multichoice(Document):
m_id = fields.IntField(min_value=1, verbose_name='MCQ Id')
m_title = fields.StringField(primary_key=True, max_length=255, verbose_name='Title')
m_question = fields.StringField(verbose_name='Question')
m_alternatives = fields.ListField(fields.StringField(),verbose_name='Alternatives')
def __str__(self):
return self.m_title
Quiz Model
from django_mongoengine import Document, EmbeddedDocument, fields
from mcqs.models import *
class quiz(Document):
q_id = fields.IntField(min_value=1, verbose_name='Quiz ID')
q_title = fields.StringField(primary_key=True, max_length=255, verbose_name='Title')
q_s_description = fields.StringField(max_length=255, verbose_name='Description')
q_questions = fields.ListField(fields.IntField(), verbose_name='Question Numbers', blank=True)
def __str__(self):
return self.q_title
MCQ Views
def view_multichoice(request, m_id):
get_md = multichoice.objects(m_question_number = m_id)
return render(request, 'mcqs/mcq.html', {'get_md':get_md})
Quiz Views
def view_quiz(request, q_id):
get_q = quiz.objects(q_id = q_id)
return render(request, 'quiz/quiz.html', {'get_q':get_q})
Current Result
Expected Result
EDIT 1
Quiz Views
from django.shortcuts import render
from django.http import HttpResponse
from .models import *
from mcqs.models import *
def view_quiz(request, q_id):
quiz_object = quiz.objects(q_id=q_id)[0]
multichoice_objects = [multichoice.objects(m_id=id) for id in quiz_object.q_questions]
get_q = [objects[0].m_question for objects in multichoice_objects if objects]
return render(request, 'quiz/quiz.html', {'get_q':get_q})
Quiz Template
{{ get_q }}
You are returning the question documents as it is. What you should be doing is, fetch the multichoice documents corresponding to the question ids, and then get the question field from each of those documents.
Change the second line in quiz views to this:
# Get the question document corresponding to given id
# objects method returns a list. Get the first one out of it.
# Here, I've assumed there's exactly 1 quiz document per ID. Handle the edge cases
quiz_object = quiz.objects(q_id = q_id)[0]
# Get the multiple choice documents corresponding to the ids in q_questions list
# Remember that objects method returns a list. Hence this is a list of lists
multichoice_objects = [multichoice.objects(m_id=id) for id in quiz_object.q_questions]
# Get the actual questions from the multichoice documents
get_q = [objects[0].m_question for objects in multichoice_objects if objects]
Ideally, you should be making multichoice as an EmbeddedDocument and the q_questions field in quiz model as EmbeddedDocumentListField. But the drawback here will be, you can't query EmbeddedDocuments independently. So you wont be able to do multichoice.objects(m_question_number=m_id).
You can read more about EmbeddedDocuments here
Related
I am making a small Django project, but I have an issue. When I write names to one form and topics to other one and press button, I want to see list of randomly attached names and topics. In my current code I donĀ“t get a list but just one name and one topic. How can I solve that problem?
My views.py file:
from django.shortcuts import render
from .losovaci_zarizeni import UvodniTabulka
from random import choice
def losovani_view(request):
form = UvodniTabulka(request.GET)
spoluzaci = request.GET.get("spoluzaci")
temata = request.GET.get("temata")
spoluzaci_list = spoluzaci.split()
temata_list = temata.split()
while True:
spoluzak = choice(spoluzaci_list)
spoluzaci_list.remove(spoluzak)
tema = choice(temata_list)
temata_list.remove(tema)
if len(spoluzaci_list)==0:
break
return render(request, "losovani.html", {"form":form, "spoluzak": spoluzak, "tema":tema})
My file with UvodniTabulka:
from django import forms
class UvodniTabulka(forms.Form):
spoluzaci = forms.CharField(max_length=500)
temata = forms.CharField(max_length=500)
Currently working on a web page and I want to show two different tables of information one is for individual foods and the other is for recipes, however I can only get the first class to pull up any information I've tested to see if the first class can pull up the recipe database and it, in fact, currently out of ideas on what to try next.
class SearchFoodResultsView(ListView):
model = Food
template_name = 'nutrihacker/search.html'
context_object_name = 'food_list'
# overrides ListView get_queryset to find names containing search term and pass them to template
def get_queryset(self):
query = self.request.GET.get('term')
if (query == None):
return Food.objects.all()
else: # If there are any foods containing the query, they will be in the resulting object_list which is used by search.html in a for loop
food_list = Food.objects.filter(
Q(name__icontains = query)
)
return food_list
class SearchRecipeResultsView(ListView):
model = RecipePreset
template_name = 'nutrihacker/search.html'
context_object_name = 'recipe_list'
# overrides ListView get_queryset to find names containing search term and pass them to template
def get_queryset(self):
query = self.request.GET.get('term')
if (query == None):
return RecipePreset.objects.all()
else: # If there are any recipes containing the query, they will be in the resulting object_list which is used by search.html in a for loop
recipe_list = RecipePreset.objects.filter(
Q(name__icontains = query)
)
return recipe_list
I am learning Django forms and am trying to save form data. I have a working form, but I can't figure out to 'do' anything with the data entered on the form. Specifically, I am trying to do the following two things:
First, once the user submits the form, load a new page that states: "You searched for 'X'".
Second, have the form data interact with an existing database. Specifically, I have a model called 'Hashtag' that has two attributes: 'search_text' and 'locations'. I think the process would work as follows:
Send X to the Model ('Hashtag'),
If X is equal to an existing hashtag.search_text object in the database, then return a page with: "The following are the locations for 'X': 'Y'
If X doesn't equal an existing hashtag.search_text object in the database, then return a page with: "The following are the locations for 'X': no locations found".
Where,
X = user-inputted form data
Y = hashtag.locations.all() in a list
Thus far, I have the below:
models.py
from django.db import models
class Hashtag(models.Model):
"""
Model representing a specific hashtag search. The model contains two attributes:
1) a search_text (eg 'trump') for which there will be only one for database entry (the row),
2) a list of locations (eg ['LA, CA', 'LA, CA', 'NY, NYC', 'London, UK', 'London, United Kingdom']) for which there may be 0+ per search_text.
"""
search_text = models.CharField(max_length=140, primary_key=True)
locations = models.TextField()
def __str__(self):
""" String for representing the Model object (search_text) """
return self.search_text
def display_locations(self):
""" Creates a list of the locations """
# ISSUE: insert correct code, something like: return '[, ]'.join(hastagsearch.location_list for location in self.location.all())
pass
forms.py
from django import forms
from django.forms import ModelForm
from .models import Hashtag
class SearchHashtagForm(ModelForm):
""" ModelForm for user to search by hashtag """
def clean_hashtag(self):
data = self.cleaned_data['search_text']
# Check search_query doesn't include '#'. If so, remove it.
if data[0] == '#':
data = data[1:]
# return the cleaned data
return data
class Meta:
model = Hashtag
fields = ['search_text',]
labels = {'search_text':('Hashtag Search'), }
help_texts = { 'search_text': ('Enter a hastag to search.'), }
views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Hashtag
from .forms import SearchHashtagForm
def hashtag_search_index(request):
""" View for index page for user to input search query """
hashtag_search = get_object_or_404(Hashtag)
# If POST, process Form data
if request.method == 'POST':
# Create a form instance and populate it with data from request (binding):
form = SearchHashtagForm(request.POST)
# Check if form is valid
if form.is_valid():
# process the form data in form.cleaned_data as required
hashtag_search.search_text = form.cleaned_data['search_text']
# the reason we can use .save() is because we associated the form with the model as a ModelForm
hashtag_search.save()
# redirect to a new URL
return HttpResponseRedirect(reverse('mapping_twitter:hashtag_search_query'))
# If GET (or any other method), create the default form
else:
form = SearchHashtagForm()
context = {'hashtag_search':hashtag_search, 'form':form}
return render(request, 'mapping_twitter/hashtag_search_query.html', context)
I am considering that a potential way to achieve this is to create another model and save the user-inputted form data there. I am wondering whether that is correct, and how that solution could be used to achieve the Second stated goal above :)
Thanks and apologies in advance if my explanation is a mess/plain wrong :/
EDIT
The EDIT below has made the following changes:
Updated models.py as per #Wiggy A.'s answer,
Updated views.py to include def results()
Included a link to the repo on GitHub.
models.py
from django.db import models
class Location(models.Model):
""" Model representing a Location, attached to Hashtag objects through a
M2M relationship """
name = models.CharField(max_length=140)
def __str__(self):
return self.name
class Hashtag(models.Model):
""" Model representing a specific Hashtag serch, containing two attributes:
1) A `search_text` (fe 'trump'), for which there will be only one per
database entry,
2) A list of `locations` (fe ['LA, CA', 'NY, NYC']), for which there
may be any number of per `search_text` """
search_text = models.CharField(max_length=140, primary_key=True)
locations = models.ManyToManyField(Location, blank=True)
def __str__(self):
""" String for representing the Model object (search_text) """
return self.search_text
def display_locations(self):
""" Creates a list of the locations """
# Return a list of location names attached to the Hashtag model
return self.locations.values_list('name', flat=True).all()
views.py
...
def results(request):
""" View for search results for `locations` associated with user-inputted `search_text` """
search_text = hashtag_search
location_list = Hashtag.display_locations()
context = {'search_text':search_text, 'location_list':location_list}
return render(request, 'mapping_twitter/results.html')
The full repo can be found here: https://github.com/darcyprice/Mapping-Data
EDIT 2
The EDIT below makes the following changes:
Updated views.py to include #Wiggy A.'s suggested amendment of def results()
Included a copy of the ERROR message received due to the updated changes.
Although I copied directly from the Mozilla tutorial (https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms), I suspect that the line: hashtag_search.search_text = form.cleaned_data['search_text'] doesn't correctly store hashtag_search.
ERROR
NameError at /search_query/
name 'hashtag_search' is not defined
Request Method: POST
Request URL: http://ozxlitwi.apps.lair.io/search_query/
Django Version: 2.0
Exception Type: NameError
Exception Value:
name 'hashtag_search' is not defined
Exception Location: /mnt/project/mapping_twitter/views.py in hashtag_search_index, line 24
Python Executable: /mnt/data/.python-3.6/bin/python
Python Version: 3.6.5
Python Path:
['/mnt/project',
'/mnt/data/.python-3.6/lib/python36.zip',
'/mnt/data/.python-3.6/lib/python3.6',
'/mnt/data/.python-3.6/lib/python3.6/lib-dynload',
'/usr/local/lib/python3.6',
'/mnt/data/.python-3.6/lib/python3.6/site-packages']
views.py
def hashtag_search_index(request):
""" View for index page for user to input search query """
# If POST, process Form data
if request.method == 'POST':
# Create a form instance and populate it with data from request (binding):
form = SearchHashtagForm(request.POST)
# Check if form is valid
if form.is_valid():
hashtag_search.search_text = form.cleaned_data['search_text']
hashtag_search.save()
# redirect to a new URL
return HttpResponseRedirect(reverse('mapping_twitter:results'))
# If GET (or any other method), create the default form
else:
form = SearchHashtagForm()
context = {'hashtag_search':hashtag_search, 'form':form}
return render(request, 'mapping_twitter/hashtag_search_index.html', context)
def results(request):
""" View for search results for `locations` associated with user-inputted `search_text` """
search_text = hashtag_search
location = get_object_or_404(Hashtag, search_text=search_text)
location_list = location.display_locations()
context = {'search_text':search_text, 'location_list':location_list}
return render(request, 'mapping_twitter/results.html', context)
Turn the locations attribute into a M2M field. That sounds like what you need here. Keep in mind that this is untested code.
models.py
from django.db import models
class Location(models.Model):
""" A model representing a Location, attached to Hashtag objects through a Many2Many relationship """
name = models.CharField(max_length=140)
def __str__(self):
return self.name
class Hashtag(models.Model):
"""
Model representing a specific hashtag search. The model contains two attributes:
1) a search_text (eg 'trump') for which there will be only one for database entry (the row),
2) a list of locations (eg ['LA, CA', 'LA, CA', 'NY, NYC', 'London, UK', 'London, United Kingdom']) for which there may be 0+ per search_text.
"""
search_text = models.CharField(max_length=140, primary_key=True)
locations = models.ManyToManyField(Location)
def __str__(self):
""" String for representing the Model object (search_text) """
return self.search_text
def display_locations(self):
""" Creates a list of the locations """
# This will return a list of location names attached to the Hashtag model
return self.locations.values_list('name', flat=True).all()
views.py
...
def results(request):
""" View for search results for `locations` associated with user-inputted `search_text` """
search_text = hashtag_search
location = get_object_or_404(Hashtag, search_text=search_text)
location_list = location.display_locations()
context = {'search_text':search_text, 'location_list':location_list}
return render(request, 'mapping_twitter/results.html')
I want to display answer subject and question in my template. How would I call these variables from my Answer class in my template?
Here is how my class looks
Model.py:
class Answer(models.Model):
subject = models.ForeignKey(Subject, help_text = u'The user who supplied this answer')
question = models.ForeignKey(Question, help_text = u"The question that this is an answer to")
runid = models.CharField(u'RunID', help_text = u"The RunID (ie. year)", max_length=32)
answer = models.TextField()
def __unicode__(self):
return "Answer(%s: %s, %s)" % (self.question.number, self.subject.surname, self.subject.givenname)
def choice_str(self, secondary = False):
choice_string = ""
choices = self.question.get_choices()
for choice in choices:
for split_answer in self.split_answer():
if str(split_answer) == choice.value:
choice_string += str(choice.text) + " "
Template:
{{ subject }}
{{ question }}
{{ answer }}?????
I am fairly new to Django and I am only a few weeks in to learning.
Values to the template are passed onto by views (through something known as a context) when they render some html, and not by the model classes as you seem to be indicating.
This also makes sense because model classes are just a schema or a representation of your database, whereas views are functions that retrieve values from the database (or not) and create dynamic content to be rendered.
Here's the link to the official tutorial on how to do it properly.
Pass the values in your views.py something like this:
from django.shortcuts import render_to_response
def display_variables(request):
subject = # get your subject and assign it a variable
question = # get your question and assign it a variable
answer = # get your answerand assign it a variable
return render_to_response('your_web_page.html',{'subject':subject,'question ':question ,'answer ':answer },context_instance=RequestContext(request))
I have models for Application and Role. Role is linked to a FK Role_type, which is linked by FK to Applications that can use those Role_types (this is a bit of an over-simplication for the question, but I think it suffices). I need a way to create a form to make a new Application, and also to create records assigning associated roles to people (although they can be left blank.)
I have gotten as far as creating the form for the Application and having the associated Role-Types appear on the page, with dropdowns to be populated with a user. Hitting submit, though, didn't create any of the associated Role records. All of my research seems to keep coming back to Inline Model Forms, but the docs aren't really making sense to me--the inputs in the example don't seem to correlate to what I need.
I know this may seem like a duplicate, but trust me when I say I've looked at every SO question that seems to relate to this!
EDIT: My POST looks like this: QueryDict: {u'roles-MAX_NUM_FORMS': [u'1000'], u'roles-1-role_type': [u'4'], u'roles-0-user': [u'1'], u'app-owner': [u'1'], u'app-name': [u'1234'], u'app-serviceTier': [u''], u'app-jiraProject': [u''], u'roles-TOTAL_FORMS': [u'2'], u'roles-1-user': [u''], u'roles-0-role_type': [u'3'], u'csrfmiddlewaretoken': [u'eGsDwtsSQJfl0'], u'roles-INITIAL_FORMS': [u'2']}>. Printing RolesFormSet gives me the exact same output (see comment below)
models.py
class Item(models.model):
name = models.CharField(max_length=255)
roles = models.ManyToManyField(User, through='Role')
class Application(Item):
other_assorted_attributes = foo
class RoleType(models.Model):
name = models.CharField(max_length=255)
class ItemTypeRoleMapping(models.Model):
''' pairs role-types (e.g., Developer) with an Item class they are relevant to'''
roleType = models.ForeignKey(RoleType)
itemType = models.CharField(max_length=255, choices=itemChoices)
class Role(models.Model):
role_type = models.ForeignKey(RoleType)
user = models.ForeignKey(User)
item = models.ForeignKey(Item)
views.py
def buildRolesFormset(itemClass):
''' given an item, build a form for all associated roles '''
roleTypesForItem = ItemTypeRoleMapping.objects.all().filter(itemType=itemClass.__name__)
applicable_roles = [{'role_type': roleType} for roleType in roleTypesForItem]
# formset = rolesFormSet(initial=initial, prefix='roles')
RoleFormSet = inlineformset_factory(Application, Role, extra=len(roleTypesForItem), can_delete=False)
formset = RoleFormSet()
for subform, data in zip(formset.forms, applicable_roles):
subform.initial = data
return formset
def new(request):
''' Create a new application '''
user = request.user
# check permission
if request.method == 'POST':
appform = AppForm(request.POST, prefix='app')
if appform.is_valid():
app = appform.save(commit=False)
rolesInlineFormSet = inlineformset_factory(Application, Role)
# pdb.set_trace()
rolesFormSet = rolesInlineFormSet(request.POST, instance=app, prefix='roles')
if rolesFormSet.is_valid():
rolesFormSet.save()
else:
print rolesFormSet.errors
app = appform.save()
# check rolesFormSet
return redirect(reverse('index'))
else:
appform = AppForm(prefix='app')
rolesFormSet = buildRolesFormset(Application)
return render(request, 'who/editapp.html',
{'appform': appform,
'rolesFormSet': rolesFormSet
})
Tricky to tell without more information, but it looks like you're not saving your rolesFormset in the view. You need to call rolesFormset.save() alongside your form.save() call. Additionally, I suppose you want to attach the roles to the created app? Something like this in your view should work:
if request.method == 'POST':
form = AppForm(request.POST)
rolesFormset = RoleForm(request.POST)
if form.is_valid() and rolesFormset.is_valid():
app = form.save()
roles = rolesFormset.save()
for role in roles:
app.roles.add(role)
return redirect(reverse('index'))
Update: Presuming the models.py is out-of-date, and Role does in fact have a foreignKey to User, the problem will be that you're setting a prefix here:
rolesFormSet = rolesInlineFormSet(request.POST, instance=app, prefix='roles')
but not in your buildRolesFormset function. In that function, do:
formset = RoleFormSet(prefix='roles')