0

I am writing a django recipe website and have a question about JSON Field and forms

I am trying to write the create recipe function for the site and wanted to do two things:

  1. I want to add text fields on mouse click similarly to adding attachments with e-mails. I want to use JSONField to do so (unless picklefield is better)

  2. i want the user to be able to edit the recipe in one textfield. I was hoping i could pack all of the steps into one text field and allow them to edit that field and then unpack them back into the steps. otherwise it might get confusing for the user to have to edit each individual step.

here are my models from the django project:

class Cookbook(models.Model):
    def __unicode__(self):
        return self.name
    name = models.CharField(max_length=50)
    pub_date = models.DateTimeField('date published')
    user = models.ForeignKey(User, related_name='cookbooks')
    recipes = models.ManyToManyField('Recipe', related_name = 'cookbooks')


class Recipe(models.Model):
    def __unicode__(self):
        return self.name
    original_cookbook = models.ForeignKey(Cookbook)
    name = models.CharField(max_length=200)
    author = models.CharField(max_length= 100)
    picture = models.ImageField(upload_to = 'Downloads', blank=True)
    pub_date = models.DateTimeField('date published', auto_now_add=True, blank=True)
    ingredients = JSONField()
    steps = JSONField()
    prep_time = models.IntegerField()

Here is the view in which I create a new recipe. Right now I am unsure how to use the JSONField in my view.

I found this link but it states "Finally, I'm not sure how to interact with forms yet, so that realm is a bit murky." Seeing that I am using a form, has this been resolved?

def createrecipe(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/index/')
    else:
        if request.method == 'POST':
            form = RecipeForm(request.POST)
            if form.is_valid():
                recipe = form.save(commit=False)
                recipe.original_cookbook = request.user.cookbooks.all()[0]
                recipe.pub_date = datetime.datetime.now()
                recipe.save()
                user = request.user
                cookbooks = user.cookbooks
                cookbook = cookbooks.all()[0]
                cookbook.recipes.add(recipe)
                return HttpResponseRedirect('/account')
        else:
            form = RecipeForm()

        return render_to_response('cookbook/createrecipe.html',
                                    {'form':form},
                              context_instance=RequestContext(request))

here is the createrecpe.html block content:

{% block content %}
    <form action="." method="POST">
        <table>
            {% csrf_token %}
            {{ form.as_table }}
        </table>
        <p><input type="submit" value="Submit"></p>
    </form>
{% endblock %}

I am having a hard time bridging the gap between the JSONField model and the view to display/enter text into the JSON field. I also am confused how to display the jsonfield in a template.

thank you for any help this has really been discouraging me,

snackerfish

snackerfish
  • 109
  • 4
  • 14

1 Answers1

0

You can use a formset here. In your case - take django-jsonfield or django-picklefield to avoid manual converting to/from data on object's saving and retrieving, and create a formset providing empty list on init.

You can manipulate it on client side using js, but do not forget to increment forms count in TOTAL_FORMS hidden input. After POSTing the form and cleaning the data you'll have formset.cleaned_data() which you could put to your PickleField without any aditional processing (and data from the field can be put as initial to formset if you'll need to edit the recipe).

ilvar
  • 5,718
  • 1
  • 20
  • 17
  • so if i wanted to use json for the recipe_ingredients i would just use JsonField instead of TextField? or do I have to make a json field and add the text field to the json field thanks @ilvar this seems perfect – snackerfish Apr 19 '12 at 16:52
  • I have figured out how to setup json but i am now getting an error in my template **Caught ValueError while rendering: No JSON object could be decoded** do i need to unpack the json or something in my template? – snackerfish Apr 19 '12 at 17:25
  • JSON field returns a Python object (usually dict or list), your problem is wrong data in DB, it's something but not correct JSON. Maybe you have put something wrong in that field. How have you populated it? What data do you have in DB in that field? – ilvar Apr 20 '12 at 03:38
  • Also, complex Python objects are not JSON-serializable, if case your Ingredients data contains something more than a list of dicts of strings (for example, model object) then you should use PickleField instead. Or better way is to save only object's PK and retrieve object on data retrieval. – ilvar Apr 20 '12 at 03:40
  • could this be happening because I have already populated all of my recipes using the textfield and now I am trying to access them as if they were jsonfield. If I have made the change from textfield to json field should i delete my database and start fresh? – snackerfish Apr 20 '12 at 14:42
  • as for the ingredient data, it will only be a list of strings but I could make it a dict by adding a number for each ingredient for example ["1":"apple","2":"butter"] but to do so I would have to figure out how to create a dictionary that has a number for each ingredient(this could be done with a loop) – snackerfish Apr 20 '12 at 15:18
  • It is not JSON. You should reformat it with any utility (maybe, python `simplejson` library) or fill from scratch with your interface. If the text in DB is not a valid JSON code then you'll surely receive an error. – ilvar Apr 20 '12 at 16:32
  • thank you for you ongoing help ilvar, I attached some new code to my question. The problem I am facing with JSONField is implementing it in a django form. - I dropped my cookbook sql and now have no errors until I try and create a recipe (see createrecipe view) – snackerfish Apr 21 '12 at 20:42
  • You can use a formset, as I said in my answer. – ilvar Apr 22 '12 at 06:37