A help in concept and a database query question (Django/Python) - python

I am trying to build a kind of news website for learning purposes.
class NewsCategory(models.Model):
category = models.CharField(max_length=50)
Note: A category can be Soccer, Tennis, business ... User can register to different news category. This choice will be saved in their preferences.
class Profile(models.Model):
user = models.ForeignKey(User, unique=True)
gender = models.CharField(max_length=1,blank=True)
preference = models.ManyToManyField(NewsCategory)
I am currently stuck on how to update the preference list of each user (the list that specifies in which categories he is interested in.)
View:
category = [(item.category) for item in NewsCategory.objects.all()]
and then I am sending the category to the template below
template:
<div id="c_b">
{% for c in category %}
<input type="checkbox" name="category[]" value="{{c}}">
<label for="{{c}}">{{c}}</label>
{% endfor %}
</div>
Questions:
What is the best way to add the checked tag next to the checkboxes that are already saved in the user's preference when I display the template.
I though of getting all the preferences users are registered for: saved_preference = user.preference.all() and then checking for each item in category if it is in saved_preference
I am also blanking out on the way to actually write that into code, and whether this should be done in the view or the template.
What is a good way to update the user preference list?
I was planning on running user.preference.clear() and then going through every item in the submitted form and running user.preference.add(the_new_preference)

You'll need to pass the complete list of categories and also an index of user-selected categories to your template. You don't need to convert the NewsCategory queryset into a list in your view, by the way:
View
categories = NewsCategory.objects.all()
user_preferences = [item.id for item in Profile.preference.all()]
The user_preferences variable will act as a lookup index for our template.
Then you loop through all the categories in the template, and check to see if it exists in the list of user preferences:
Template
<div id="c_b">
{% for c in categories %}
<input type="checkbox" name="category[]" id="id_{{ c.category }}" value="{{ c.id }}" {% if c.id in user_preferences %}checked="checked"{% endif %} />
<label for="id_{{ c.id }}">{{ c.category }}</label>
{% endfor %}
</div>
Update - saving user preferences
There is no hard and fast rule here. The main consideration, as far as I am concerned, would be minimising database hits. You can just clear the user preferences, like you say, and add the new ones - in fact, this is how Django's admin handles it. Just make use of Django's transaction management:
from django.db import transaction
#transaction.commit_manually
def add_preferences(user, preferences):
user.preference.clear()
for pref in preferences:
user.preference.add(pref)
transaction.commit()

You should learn about forms and model forms in django. It would be the best way for both adding and changing. Forms will do the most of job for you.

Related

How to save multiple model object instances using one single form in django?

I have the three following models:
class AnswerItem(models.Model):
item_name = models.CharField(max_length=320)
item_number = models.PositiveIntegerField()
class AnswerMenu(models.Model):
menu_name = models.CharField(max_length=320)
answer_item = models.ForeignKey(AnswerItem)
class QuestionAnswer(models.Model):
answer = models.ForeignKey(AnswerMenu)
answer_item = models.ForeignKey(AnswerItem)
Answer menus are currently displayed on a single page using a list view, with the following template:
{% for answer_menu in answer_menus %}
<div>{{ answer_menu.menu_name }}</div>
{% for answer_item in answer_menu %}
<p>
<label>
<input id="{{ answer_item.pk }}" name="{{ answer_menu.pkĀ }}" type="radio">
</label>
</p>
Now, the trouble I have is I would like to create a single form to save all selected answers using the radio buttons on the page. Since there are multiple answer menus shown on the page, posting through this form would create several QuestionAnswer items.
How would you approach this?

How to dynamically activate categories in main navigation as products are added to the category?

I am working on a site where users upload products. When the user uploads a product, they can currently select from about 50 categories.
I would like to have all categories listed in my main navigation, however they won't all have products listed in the category in the early stages of the site. The ones that don't should not be linked and the text would be greyed out.
The part that is confusing is how to manipulate the main nav via a view. All of my views are for specific pages, so I'm not sure how to have a view function that runs prior to each page's view function, sort of like a custom middleware in Node + Express routing.
Or perhaps this is not Djangoic, and there is a better method to achieve this?
Thanks for any tips.
Let's say you have a foreign-key relationship from Product to Category in your models. That being said, you can render a link only if that category has products in it:
template:
{% for category in categories %}
{% if category.product_set.count > 0 %}
{{ category.title }}
{% else %}
{{ category.title }}
{% endif %}
{% endfor %}
and if you want to prevent users from accessing the category pages with no product manually (e.g. the user enters example.com/category/xxx manually), you can add as simple if condition before rendering the template:
views.py
def category_detail_view(request, category_pk):
category = get_object_or_404(Category, pk=category_pk)
if category..product_set.count == 0:
# redirect to a custom page
...

Django - dropdown form with multiple select

I need guidance building a django dropdown forms.Form field in which I can select multiple choices. I need to select multiple locations on the office field of the form.
When submitted, the form needs to return a list of the chosen offices (e.g. ["New York", "Los Angeles"] or ["Austin"]). Returning a tuple is also acceptable.
The best I can do right now is build a multipleChoiceField for office with the following:
from django import forms
class my_Form(forms.Form):
OPTIONS = [
("0", "*ALL"),
("1", "New York"),
("2", "Los Angeles"),
]
office = forms.MultipleChoiceField(
choices=OPTIONS,
initial='0',
widget=forms.SelectMultiple(),
required=True,
label='Office',
)
resulting in this form field layout:
However, I would like this field to be a dropdown, to take up less space on the page.
I found this djangosnippet but (1) a few people have mentioned it appears out of date (I can't confirm), and (2) I first want to check if a built-in django form/widget setup can fulfill this task before using custom code.
"Dropdown" boxes don't support multiple selection in HTML; browsers will always render it as a flat box as your image shows.
You probably want to use some kind of JS widget - Select2 is a popular one. There are a couple of Django projects - django-select2, django-easy-select - that aim to make it simple to integrate that into your form; I have no experience with either of them.
(And yes, that snippet - like many things on Djangosnippets - is massively out of date; "newforms" was renamed to "forms" even before version 1.0 of Django.)
You can choose multiple choices by using Django select2. Include below code in your respective HTML file.
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<select class="select_field_class" multiple="multiple" name="option" id="option">
<option value="">Enter the option</option>
{% for option in options %}
<option value="{{ option.id }}">{{ option.name }}</option>
{% endfor %}
</select>
$('.select_field_class').select2( { placeholder: "Select here", maximumSelectionSize: 100 } );
This is late but hope it helps someone else.
You can also do it a combination of django forms and a select2 widget Select2MultipleWidget to make it look cleaner.
class YourCreateForm(forms.ModelForm):
CHOICES = (("address1","address1"), ("address2","address2"))
address=forms.MultipleChoiceField(choices=CHOICES,widget=Select2MultipleWidget)
class Meta:
model = YourModel
fields = ("field1","address",)
Do not forget to install and import the django select2 widgets
As I said in a similar question, one suggestion is use Bootstrap with Python.
forms.py
(...)
class yourForm(forms.Form):
options = forms.MultipleChoiceField(
choices=OPTIONS, widget=forms.CheckboxSelectMultiple(),
label="myLabel", required=True, error_messages={'required': 'myRequiredMessage'})
view.py
def anything(...):
(...)
form = yourForm( )
(...)
return render(request, "myPage.html", {'form': form})
myPage.html
(...)
{% csrf_token %}
{% for field in form %}
<div class="col-md-12 dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{{ field.label_tag }}
<span class="caret"></span>
</button>
<div class="dropdown-menu">
<div>{{ field }}</div>
</div>
</div>
{% endfor %}
(...)

D3.js Directed Graph Django Integration

I have a simple Django application that queries a database and displays the fields of the objects returned. I was wondering what would be the best way to go about integrating this directed graph visualisation into my project; I've never worked with d3 until now.
Allow me to explain my application. At the moment, it's simply a form that allows users to query contents of the database regarding information on books, by entering the unique ID of a book. This works fine, the contents are displayed through the use of a template.
What I wish to do is used one of the fields of the queried objects to push data into the graph example above, and simply display this graph in a new window when a text-link is pressed.
Here's my application structure:
Code
myapp.models.py:
from django.db import models
class Book(models.Model):
uid = models.IntegerField(primary_key=True)
title = models.CharField(max_length=30)
related_books = models.CharField(max_length=2048)
class Meta:
db_table = u'books'
The field related_books contains the data I wish to graph. The data is stored in the format rel_book1 rel_book2 rel_book3 ... where each book is related to the queried Book object, there are n related books for each object, but there is at least always two.
myproject.templates.search.html:
<form action="" method="get">
<label for="id_q">Search:</label>
<input id="id_q" name="q" type="text">
<input type="submit" value="Submit">
{% if found_entries %}
<ul>
{% for i in found_entries %}
{{ i.uid }} {{ i.title }} {{ value|linebreaks }}
{% endfor %}
</ul>
{% endif %}
</form>
So this is where I'd like to display the graph; in a new window when a text-link is pressed.
myapp.views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from myapp.search import get_query
from myapp.models import Book
def search(request):
query_string = ''
found_entries = None
if ('q' in request.GET) and request.GET['q']:
query_string = request.GET['q']
found_entries = Book.objects.filter(uid=query_string)
return render_to_response('search.html',
{ 'query_string': query_string, 'found_entries': found_entries },
context_instance=RequestContext(request))
So just to reiterate, a user enter a unique ID for a given book and contents of the database related to that book are displayed. At the moment the ID and title are displayed, I'd also like to display a link to the directed graph example.
So my question is, how would I go about extracting the information out of the field related_books when the Book model is queried, so that I can push this data into the graph example to generate graphs for each Book object generated?
Thanks for bearing with me!
It seems to me you already have enough information. Your view returns book objects that match the filter, and related_books is a member of the Book class.
You'd simply need to generate a link on the fly by iterating over the related_books attribute of each book, e.g.
{% for book in found_entries %}
# print out whatever results here
<a href="graphing_page.html?contents=
{% for content in book.related_books %}content{% endfor %}
">Graph this</a>
{% endfor %}
I'm not sure what parameters the d3 library takes, but a list of connected components seems reasonable.

django create profile or page for object

I have a venue object and want to have either a profile/page associated with the object which contains venue specific info like price, hours of operation and so on. Here is my venue object
class Venue(model.Models):
name=models.CharField(max_length=100)
# ...
image=models.ImageField(upload_to=...)
Now I have no idea where to go next with the VenueProfile model and the view which will bind these together this all I can think of:
class VenueProfile(model.Models):
venue=models.OneToOneField(Venue, related_name='venueProfile')
# ...
# info i want stored about the venue
# ...
Can someone please help me figure out if
This is the right type of model setup for a objects profile/page
How do I write a view for this? Connect the venue model with the profile model and render a template.
Yes, you are taking a right approach. Usually when you want to have a decoupled entity and then later if you want to associate attributes with it (e.g. profile to a user), OneToOneField is very useful.
As far as connecting, since these are two separate tables, there is no really good way of merging these. However since you are using related_name parameter, even though models are different, you can easily access attributes of the other model by:
venue = Venue.objects.get(...)
venue.name <- Venue attribute
venue.venueProfile.foo <- VenueProfile attribute
One down side of this approach is that there are database queries involved. To make this more efficient, you can do either one of these approaches. The first approach however is more efficient since for that, Django will use SQL join which is faster to "Python's" joins.
profile = VenueProfile.objects.filter(...).select_related('venue')[0]
venue = profile.venue <- no extra query
or this method for here Django will do the join in Python so slower:
venue = Venue.objects.filter(...).prefetch_related('venueProfile')[0]
At this point, these are just regular objects so you can easily pass them to template. The following is a simple view, urlconfig and template example:
def all_venues(request):
# note that querying profiles...
venues = VenueProfile.objects.all().select_related('venue')
return render_to_response('template.html', {'venues':venues})
def venue(request, venue_id):
venue = VenueProfile.objects.filter(venue__pk=venue_id).select_related('venue')
if len(venue) == 1:
venue = venue[0]
else:
raise Http404
...
urlconfig:
url(r'^venue/all/$', 'all_venues', name='all_venues'),
url(r'^venue/(?P<venue_id>\d+)/$', 'venue', name='venue'),
and template
{% load url from future %}
{% for venue_profile in venues %}
{% with venue=venue_profile.venue profile=venue_profile %}
<ul>
<li>
<a href="{% url 'venue' venue_id=venue.pk %}">
{{ venue.name }}</a><br>
<img href="{{ venue.image.url }}"><br>
{{ profile.foo }}
</li>
</ul>
{% endwith %}
{% empty %}
No venues
{% endfor %}

Categories