0

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:

  1. 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.

  2. 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)

2 Answers 2

1

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()
Sign up to request clarification or add additional context in comments.

2 Comments

I think this pretty much solves the first issue I had! quick html clarification: in the label did you mean to write ` for="id_{{ c.category }}` instead of for="id_{{ c.id }}"? Do you think it is a good approach to clear the list and then update it all every time the form is submitted? I am suggesting this because I don't think there a straightforward way to know if a user removed/added a preference (or did both).
Sorry, typo. That is what I meant, yes. Re. updating preferences, I'll add an update to my answer.
0

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.

2 Comments

I can see how a form will help me add one entry of NewsCategory, or one instance of user. However I fail to see how the manytomany field can be incorporated into the form, or used to edit the preference list of a user.
profile = user.get_profile() #i.e. form = ProfileForm(instance=profile) #there is the model form created from existing profile. By default ManyToMany fields will be shown as a multi select.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.