开发者

Creating editable HTML tables with Django

I'm trying to create a Django app where the user can make a list of movies. Each time the user logs in, their list of movies will be presented to them in a table. The table will have three columns: one for the movie's name, one for the genre, and another that will contain delete buttons that will allow the user to delete the row corresponding to the button. The user can add rows to the table by filling in a textbox with the name of the movie, and selecting a genre from a drop down menu, and then pressing an "Add" button. The "Add" and "Delete" buttons are the only way by which the user can edit the table.

Is there any Django shortcuts to creating such an editable table? I thought this might be something that is appropriate for formsets, but I can't figure out how to do it. Also, it has been difficult to google "Django tables" as the results seem to be about database tables.

This is the model that I am currently trying to 开发者_C百科use:

class MovieList(models.Model):
    user = models.ForeignKey(User)
    movie = models.ForeignKey(Movie)

class Movie(models.Model):
    genre = models.ForeignKey(Genre)
    name = models.CharField(max_length=300)

class Genre(models.Model):
    name = models.CharField(max_length=200)

Any help would be very much appreciated.


There are several ways you can solve this. Though it doesn't really use a shortcut i can't see what's wrong about rendering the table by a standard view and a attach a form for entering new entries to it.

If you are looking for a shortcut and some additional convenience django-tables might be for you.

Of course you could use jQuery to make the process even more dynamic so that people can add and delete items without reloading the whole page: Something similar to Django's dynamic inlines in the admin. If you decide to take this route you should take a closer look a django-dynamic-formsets or at one of the several grid-plugins for jQuery. jqGrid to name one.


You can use ajax requests and reload only the tbody after the user add or delete a movie, here is a example that i used before

In html template you will have your table and inside the script tag you will have a function to load the table, to delete a movie, and to add a movie

template 1

<table>
    <thead>
        <th>Name</th>
        <th>Genre</th>
        <th>Action</th>
    </thead>
    <tbody id="table_movie_id">
        {% if movies %}
        {% for movie in movies %}
        <tr>
            <td>{{movie.name}}</td>
            <td>{{movie.genre}}</td>
            <td>
                <button value="{{movie.id}}" onclick=deleteMovie(this.value)>
                    delete
                </button>
            </td>
        </tr>
        {% endfor %}
        {% endif %}
    </tbody>
    <tfoot>
        <form method="POST" onsubmit=addMovie(event)>
            {% csrf_token %}
            <td>
                <label>Name</label>
                {{ form.name }}
            </td>
            <td>
                <label>Genre</label>
                {{ form.genre }}
            </td>
            <td>
                <button type="submit">
                    add
                </button>
            </td>
        </form>
    </tfoot>
</table>
<script>
    function loadTable() {
        let xhttpTableMoves = new XMLHttpRequest()
        xhttpTableMovies.onreadystatechange = function (data) {
            if (this.readyState === 4 && this.status === 200) {
                document.getElementById("table_movie_id").innerHTML = this.response
            }
        }
        xhttpTableMoves.open("GET", "./url_to_api/load_table/", true)
        xhttpTableMoves.send()
    }

    function deleteMovie(idMovie) {
        const request = new Request(`./url_to_django/delete-movie/${idMovie}`,
            {
                method: "DELETE",
                headers: { 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value }
            }
        )
        fetch(request, {
            method: "DELETE",
            mode: 'same-origin'
        }).then(
            function (response) {
                if (response.status === 200) {
                    loadTable()
                } else {
                    alert("error")
                }
            }
        )
    }

    function addMovie(e) {
        e.preventDefault()
        const dataToBackEnd = new FormData()
        dataToBackEnd.append("name", document.getElementById("id_name").value)
        dataToBackEnd.append("genre", document.getElementById("id_genre").value)
        const request = new Request('./url_to_django/add-movie/',
        {
            method: 'POST',
            headers: { 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value },
            body: dataToBackEnd
        })
        fetch(request, {
            method: 'POST',
            mode: 'same-origin'
        }).then(
            function(response) {
                if (response.status === 201) {
                    loadTable()
                } else {
                    alert("error")
                }
            }
        )

    }
</script>

And in another template you will have only the tbody part

template2.html

<tbody id="table_movie_id">
    {% if movies %}
    {% for movie in movies %}
    <tr>
        <td>{{movie.name}}</td>
        <td>{{movie.genre}}</td>
        <td>
            <button value="{{movie.id}}" onclick=deleteMovie(this.value)>
                delete
            </button>
        </td>
    </tr>
    {% endfor %}
    {% endif %}
</tbody>

In your urls you have to set routes for this ajax calls

urls.py

urlpatterns = [path(
        'url_to_django/delete-movie/<int:idmovie>',
        views.delete_movie, 
        name='delete_movie'),
    path(
        'url_to_django/add-movie/',
        views.add_movie, 
        name='add_movie'),
    path(
        'url_to_django/load_table/',
        views.load_table, 
        name='load_table')]

And in your views.py you will have something like

    def load_table(request, codorcam):
        if request.method == "GET":
            if request.user:
                movies = [] # here your movie query to database
                return render(request, 'orcs/template2.html', {"movies": movies})
            else:
                return HttpResponse(status=403)
        else:
            return HttpResponse(status=405)

    def delete_movie(request, idmovie):
        if request.method == "DELETE":
            if request.user:
                movie_to_delete = Movie.objects.get(id=idmovie)
                movie_to_delete.delete()
                return HttpResponse(status=200)
            else:
                return HttpResponse(status=403)
        else:
            return HttpResponse(status=405)

def add_movie(request, codorcam):
    if request.method == "POST":
        if request.user:
            form = formMovie(request.POST) #the form created in forms.py to add the movie
            if form.is_valid():
                name = form.cleaned_data['name']
                genre = form.cleaned_data['genre']
                new_movie = Movie(
                    name=name,
                    genre=genre,
                )
                new_movie.save()
                return HttpResponse(status=201)
            else:
                return HttpResponse(status=400)
        else:
            return HttpResponse(status=403)
    else:
        return HttpResponse(status=405)

You can also reload only the table row of reload the tbody if you want

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜