Dies ist eine Fortsetzung von diesem Artikel. Eine "projektähnliche Einheit" ist ein "Projekt" in einem Task-Management-Tool usw. Da das Theater verwaltet wird, entspricht die "Performance" diesem.
---> GitHub Repository (Python 3.8.1, Django 3.0.3)
Letztes Mal habe ich über die Dateneingabeschnittstelle nachgedacht, die zu "Leistung" gehört. Dieses Mal möchte ich über einen Mechanismus nachdenken, mit dem andere Benutzer als ich eingeladen und zu den Mitgliedern der "Performance" hinzugefügt werden können.
—— Ermöglicht dem Eigentümer einer „Aufführung“, eine „Einladung“ für ein bestimmtes Konto zu erstellen.
Diejenigen, die einladen
Eingeladen
In dieser Web-App ["Performance User"](https://qiita.com/satamame/items/959e21ade18c48e1b4d6#%E5%85%AC%E6%BC%94%E3%83%A6%E3%83%BC% E3% 82% B6% E3% 81% AE% E3% 83% A2% E3% 83% 87% E3% 83% AB) auf die von Django verwalteten Konten und jede "Leistung" Der Teilnahmestatus ist zugeordnet. Wenn die eingeladene Person "Beitreten" auswählt, wird daher ein neuer "Leistungsbenutzer" erstellt.
Es hat die folgenden Felder.
Feld | Inhalt |
---|---|
production | Eingeladene "Leistung" |
inviter | Einladende Person(Von Django verwaltete Konten) |
invitee | Eingeladene Person(Von Django verwaltete Konten) |
exp_dt | Ablaufdatum der Einladung |
--Wenn der Eigentümer von "Leistung" den Bildschirm "Mitgliederliste" anzeigt, wird die von ihm erstellte "Einladungskarte" angezeigt.
from datetime import datetime, timezone
from django.conf import settings
from django.db import models
class Invitation(models.Model):
'''Einladung zur Truppe
'''
production = models.ForeignKey(Production, verbose_name='Performance',
on_delete=models.CASCADE)
inviter = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name='Einladende Person',
related_name='inviter', on_delete=models.CASCADE)
invitee = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name='Eingeladene Person',
related_name='invitee', on_delete=models.CASCADE)
exp_dt = models.DateTimeField(verbose_name='Frist')
class Meta:
verbose_name = verbose_name_plural = 'Einladung zur Truppe'
ordering = ['exp_dt']
def __str__(self):
return f'{self.invitee}Zu{self.production}Einladung an'
def expired(self):
'''Gibt zurück, ob diese Einladung abgelaufen ist
'''
now = datetime.now(timezone.utc)
return now > self.exp_dt
--Production
ist in dieser Web-App definiert (https://qiita.com/satamame/items/959e21ade18c48e1b4d6#%E5%85%AC%E6%BC%94-%E3%83%97%E3% 83% AD% E3% 82% B8% E3% 82% A7% E3% 82% AF% E3% 83% 88% E7% 9A% 84% E5% 8D% 98% E4% BD% 8D-% E3% 81 % AE% E3% 83% A2% E3% 83% 87% E3% 83% AB) Dies ist ein Modell für "Leistung".
Das Folgende ist eine Beschreibung von Ansicht und Vorlage. Da es in einer Anwendung namens "Produktion" erstellt wird, wird die URL als "Produktion: usr_list" angegeben. Informationen zum Schreiben von "urls.py" für den Aufruf finden Sie unter Quelle für "Produktion / URLs.py". Bitte.
Erstellen Sie eine Ansicht, die "CreateView" erbt, um eine Einladung zu erstellen.
views.py
from django.views.generic.edit import CreateView
from django.contrib import messages
from django.contrib.auth import get_user_model
from .view_func import *
from .models import Production, ProdUser, Invitation
class InvtCreate(LoginRequiredMixin, CreateView):
'''Zusätzliche Ansicht der Einladung
'''
model = Invitation
fields = ()
views.py
def get(self, request, *args, **kwargs):
'''Handler, um die Anforderung zum Zeitpunkt der Anzeige zu erhalten
'''
#Überprüfen Sie den Besitz, um Zugriff auf Leistungsbenutzer zu erhalten
prod_user = test_owner_permission(self)
#Produktion als Attribut der Sicht haben
#Anzeige als festes Element in der Vorlage
self.production = prod_user.production
return super().get(request, *args, **kwargs)
Production / View_func.py
für die Funktionsweise dieser Methode. ..views.py
def post(self, request, *args, **kwargs):
'''Handler, um die Anfrage beim Speichern zu erhalten
'''
#Überprüfen Sie den Besitz, um Zugriff auf Leistungsbenutzer zu erhalten
prod_user = test_owner_permission(self)
#"ID der eingeladenen Person" in das Formular eingegeben
invitee_value = request.POST['invitee_id']
#Haben Sie einen passenden Benutzer als Attribut der Ansicht
user_model = get_user_model()
invitees = user_model.objects.filter(username=invitee_value)
if len(invitees) > 0:
self.invitee = invitees[0]
# prod_user,Produktion als Attribut der Sicht haben
#Zur Verwendung während der Validierung und Lagerung
self.prod_user = prod_user
self.production = prod_user.production
return super().post(request, *args, **kwargs)
――Auf dem Bildschirm zum Erstellen einer Einladung wird im Kontext der Benutzeroberfläche die "eingeladene Person" als "eingeladene Person" geschrieben.
settings.AUTH_USER_MODEL
eine Zeichenfolge ist.views.py
def form_valid(self, form):
'''Nach bestandener Validierung
'''
#Hinzufügen fehlgeschlagen, wenn der POST-Handler den Benutzer nicht zum Einladen veranlasst hat
if not hasattr(self, 'invitee'):
return self.form_invalid(form)
#Benutzer-ID-Liste der Leistungsbenutzer
prod_users = ProdUser.objects.filter(production=self.production)
prod_user_user_ids = [prod_user.user.id for prod_user in prod_users]
#ID-Liste der eingeladenen Benutzer
invitations = Invitation.objects.filter(production=self.production)
current_invitee_ids = [invt.invitee.id for invt in invitations]
#Es ist nicht möglich, Performance-Benutzer oder eingeladene Benutzer einzuladen.
if self.invitee.id in prod_user_user_ids\
or self.invitee.id in current_invitee_ids:
return self.form_invalid(form)
#Legen Sie jedes Feld des Datensatzes fest, den Sie hinzufügen möchten
instance = form.save(commit=False)
instance.production = self.production
instance.inviter = self.prod_user.user
instance.invitee = self.invitee
#Einsendeschluss ist 7 Tage
#Standardmäßig in UTC gespeichert, aber für alle Fälle UTC angeben
instance.exp_dt = datetime.now(timezone.utc) + timedelta(days=7)
messages.success(self.request, str(instance.invitee) + "Wurde eingeladen.")
return super().form_valid(form)
Felder
leer ist (weil Formular
nichts zu validieren hat), wird jeder Benutzer, der versucht, eine Einladung zu erstellen, diese Methode durchlaufen.views.py
def get_success_url(self):
'''Geben Sie das Übergangsziel dynamisch an, wenn das Hinzufügen erfolgreich ist
'''
prod_id = self.prod_user.production.id
url = reverse_lazy('production:usr_list', kwargs={'prod_id': prod_id})
return url
def form_invalid(self, form):
'''Wenn das Hinzufügen fehlschlägt
'''
messages.warning(self.request, "Ich konnte dich nicht einladen.")
return super().form_invalid(form)
get_success_url ()
und form_invalid ()
wenn es fehlschlägt.Produktion: Benutzerliste
) ist die Ansicht (Bildschirm" Mitgliederliste "), in der Sie versuchen, die Schaltfläche" Einladen "zu platzieren.invitation_form.html
{% extends 'base.html' %}
{% block content %}
<h1 style="margin: 0px;">
<a href="{% url 'production:usr_list' prod_id=view.production.id %}">◀</a>
Einladung zur Truppe
</h1>
<div> </div>
<form method="post">
{% csrf_token %}
<table>
<tr><th>Performance</th><td>{{ view.production }}</td></tr>
<tr><th>ID der einladenden Person</th><td><input type="text" name="invitee_id" /></td></tr>
</table>
<input type="submit" value="Einladung">
</form>
{% endblock %}
invudee_id
ein und senden Sie es mit der Schaltfläche" Einladen ".Der Bildschirm, auf dem die von Ihnen erstellte Einladung angezeigt wird, ist der Bildschirm "Mitgliederliste". Wir werden hier auch einen "Einladen" -Button einrichten. Das Benutzerszenario ist wie folgt.
views.py
from django.views.generic import ListView
from django.core.exceptions import PermissionDenied
class UsrList(LoginRequiredMixin, ListView):
'''ProdUser-Listenansicht
'''
model = ProdUser
def get(self, request, *args, **kwargs):
'''Handler, um die Anforderung zum Zeitpunkt der Anzeige zu erhalten
'''
#Erhalten Sie Leistungsbenutzer Zugriffsinformationen und überprüfen Sie die Zugriffsrechte
prod_user = accessing_prod_user(self, kwargs['prod_id'])
if not prod_user:
raise PermissionDenied
#Machen Sie es zu einem Ansichtsattribut, damit auf es aus der Vorlage verwiesen werden kann
self.prod_user = prod_user
#Machen Sie es zu einem Attribut der Ansicht, um die eingeladenen Benutzer anzuzeigen
self.invitations = Invitation.objects.filter(production=prod_user.production)
return super().get(request, *args, **kwargs)
#Folgendes wird weggelassen
―― Ursprünglich handelt es sich um eine Ansicht, in der eine Liste der "Leistungsbenutzer" angezeigt wird. Um jedoch eine Liste der Einladungen auf demselben Bildschirm anzuzeigen, werden die Einladungen auf Ansichtsattribute ("Einladungen") festgelegt, damit auf sie aus der Vorlage verwiesen werden kann. ――Im vorherigen Abschnitt habe ich "Einladungskarte, die ich gemacht habe" geschrieben, aber genau genommen habe ich "Einladungskarte, die zu dieser Aufführung einlädt" erhalten. Der Grund ist, dass es angezeigt wird, auch wenn sich der Eigentümer der "Leistung" ändert.
Es wird nur der Teil extrahiert, der die Einladung anzeigt. Um das Ganze zu sehen, gehen Sie zu Code on GitHub.
produser_list.html
{% if view.prod_user.is_owner and view.invitations %}
<div style="border:solid thin lightgray; border-radius:10px; padding: 10px; margin:5px 0 20px;">
<p><strong>Benutzer einladen</strong></p>
<table>
<tr>
<th>Benutzeridentifikation</th>
<th>Nachname</th>
<th>Name</th>
<th>Einladungsfrist</th>
</tr>
{% for item in view.invitations %}
<tr>
<td>{{ item.invitee.username }}</td>
<td>{{ item.invitee.last_name }}</td>
<td>{{ item.invitee.first_name }}</td>
{% if item.expired %}
<td style="color:red;">{{ item.exp_dt }}</td>
{% else %}
<td>{{ item.exp_dt }}</td>
{% endif %}
<td><a href="{% url 'production:invt_delete' pk=item.id from='usr_list' %}" class="deletelink">Löschen</a></td>
</tr>
{% endfor %}
</table>
</div>
{% endif %}
Der Bildschirm, auf dem die Einladung angezeigt wird, die Sie erhalten haben, ist der Bildschirm "Teilnehmende Aufführungen". Ursprünglich ist es ein Bildschirm, auf dem eine Liste der teilnehmenden Aufführungen angezeigt wird. Genau wie beim Anzeigen der erstellten Einladung wird der Bereich für die Einladung jedoch nur angezeigt, wenn die Bedingungen erfüllt sind.
views.py
class ProdList(LoginRequiredMixin, ListView):
'''Produktionslistenansicht
Das Modell ist ProdUser, da nur die Leistungen des angemeldeten Benutzers angezeigt werden.
'''
model = ProdUser
template_name = 'production/production_list.html'
def get(self, request, *args, **kwargs):
'''Handler, um die Anforderung zum Zeitpunkt der Anzeige zu erhalten
'''
#Machen Sie es zu einem Ansichtsattribut, um Einladungen an die Truppe anzuzeigen
now = datetime.now(timezone.utc)
self.invitations = Invitation.objects.filter(invitee=self.request.user,
exp_dt__gt=now)
return super().get(request, *args, **kwargs)
#Folgendes wird weggelassen
expired ()
wird nicht verwendet, aber das QuerySet filter ()
wird zum Extrahieren verwendet.Es wird nur der Teil extrahiert, der die Einladung anzeigt. Um das Ganze zu sehen, gehen Sie zu Code auf GitHub.
production_list.html
{% if view.invitations %}
<div style="border:solid thin lightgray; border-radius:10px; padding: 10px; margin:5px 0 20px;">
<p><strong>Eingeladene Gruppe</strong></p>
<table>
<tr>
<th>Leistungsname</th>
<th>Einladungs-ID</th>
<th>Einladungsfrist</th>
</tr>
{% for item in view.invitations %}
<tr>
<td>{{ item.production }}</td>
<td>{{ item.inviter.username }}</td>
{% if item.expired %}
<td style="color:red;">{{ item.exp_dt }}</td>
{% else %}
<td>{{ item.exp_dt }}</td>
{% endif %}
<td>
<a href="{% url 'production:prod_join' invt_id=item.id %}" class="addlink">Beteiligung</a>
<a href="{% url 'production:invt_delete' pk=item.id from='prod_list' %}" class="deletelink">Löschen</a>
</td>
</tr>
{% endfor %}
</table>
</div>
{% endif %}
Beim Anzeigen der von mir erstellten und erhaltenen Einladungen habe ich in der Vorlage die Schaltfläche "Löschen" eingefügt.
Erstellen Sie eine Ansicht, auf die Sie über diesen Link zugreifen können (product: invoke_delete
).
views.py
from django.views.generic.edit import DeleteView
class InvtDelete(LoginRequiredMixin, DeleteView):
'''Einladungs-Löschansicht
'''
model = Invitation
template_name_suffix = '_delete'
-- template_name_suffix
scheint standardmäßig'_confirm_delete 'zu sein.
Dieser Bereich ist Ihre Wahl.
views.py
def get(self, request, *args, **kwargs):
'''Handler, um die Anforderung zum Zeitpunkt der Anzeige zu erhalten
'''
#Überprüfen Sie, ob Sie der Eigentümer der Aufführung oder der eingeladene Teilnehmer der Einladung sind
invt = self.get_object()
prod_id = invt.production.id
prod_user = accessing_prod_user(self, prod_id)
is_owner = prod_user and prod_user.is_owner
is_invitee = self.request.user == invt.invitee
if not (is_owner or is_invitee):
raise PermissionDenied
return super().get(request, *args, **kwargs)
views.py
def post(self, request, *args, **kwargs):
'''Handler, um die Anfrage beim Speichern zu erhalten
'''
#Überprüfen Sie, ob Sie der Eigentümer der Aufführung oder der eingeladene Teilnehmer der Einladung sind
invt = self.get_object()
prod_id = invt.production.id
prod_user = accessing_prod_user(self, prod_id)
is_owner = prod_user and prod_user.is_owner
is_invitee = self.request.user == invt.invitee
if not (is_owner or is_invitee):
raise PermissionDenied
return super().post(request, *args, **kwargs)
--Das gleiche, was der POST-Handler tut, ist dasselbe wie GET. Wenn Sie sich beim Duplizieren unwohl fühlen, können Sie es zu einer Methode machen.
views.py
def get_success_url(self):
'''Geben Sie das Übergangsziel dynamisch an, wenn das Löschen erfolgreich ist
'''
if self.kwargs['from'] == 'usr_list':
prod_id = self.object.production.id
url = reverse_lazy('production:usr_list', kwargs={'prod_id': prod_id})
else:
url = reverse_lazy('production:prod_list')
return url
def delete(self, request, *args, **kwargs):
'''Nachricht beim Löschen
'''
result = super().delete(request, *args, **kwargs)
messages.success(
self.request, str(self.object) + "Wurde gelöscht.")
return result
Da der Parameter "from" zur Link-URL der Schaltfläche "Löschen" hinzugefügt wurde, wird das Rückgabeziel anhand dieses Parameters sortiert.
Sie können mit self.kwargs auf URLConf zugreifen, auch wenn Sie sich nicht in den Methoden get () oder post () befinden.
Die URLConf
wird in Production / urls.py
wie folgt angegeben (> Quelle ).
path('invt_delete/<int:pk>/<str:from>/', views.InvtDelete.as_view(), name='invt_delete'),
Es ist eine einfache Seite mit nur einer Schaltfläche "Löschen" und einer Schaltfläche "Abbrechen".
invitation_delete.html
{% extends 'base.html' %}
{% block content %}
<h1 style="margin: 0px;">
{% if view.kwargs.from == 'usr_list' %}
<a href="{% url 'production:usr_list' prod_id=object.production.id %}">◀</a>
{% else %}
<a href="{% url 'production:prod_list' %}">◀</a>
{% endif %}
Einladung zur Truppe entfernen
</h1>
<form method="post">{% csrf_token %}
<p>Möchten Sie diese Einladung löschen?</p>
<input type="submit" value="löschen">
<input type="button"
{% if view.kwargs.from == 'usr_list' %}
onclick="location.href='{% url 'production:usr_list' prod_id=object.production.id %}'"
{% else %}
onclick="location.href='{% url 'production:prod_list' %}'"
{% endif %}
value="Stornieren">
</form>
<table>
<tr><th>Performance</th><td>{{ object.production }}</td></tr>
<tr><th>ID der eingeladenen Person</th><td>{{ object.invitee.username }}</td></tr>
<tr><th>Nachname</th><td>{{ object.invitee.last_name }}</td></tr>
<tr><th>Name</th><td>{{ object.invitee.first_name }}</td></tr>
<tr><th>Frist</th>
{% if object.expired %}
<td style="color:red;">{{ object.exp_dt }}</td>
{% else %}
<td>{{ object.exp_dt }}</td>
{% endif %}
</tr>
</table>
{% endblock %}
Bei Auswahl von "Verbinden" wird ein neuer "Leistungsbenutzer" erstellt. Erstellen Sie daher die folgende "CreateView". Der Name der Vorlage lautet jedoch eindeutig "product_join.html".
views.py
from django.http import Http404
class ProdJoin(LoginRequiredMixin, CreateView):
'''Anzeigen, um an der Aufführung teilzunehmen
'''
model = ProdUser
fields = ('production', 'user')
template_name = 'production/production_join.html'
success_url = reverse_lazy('production:prod_list')
--Die in "Felder" angegebenen "Produktion" und "Benutzer" werden nicht vom Benutzer eingegeben, sondern ausgeblendet und in die Vorlage eingebettet, damit sie von "Formular" empfangen werden können. ―― Natürlich können Sie es mit dem Code festlegen, wie Sie es in ["Mechanismus zum Erstellen von Einladungen"](#Mechanismus zum Erstellen von Einladungen) getan haben.
views.py
def get(self, request, *args, **kwargs):
'''Handler, um die Anforderung zum Zeitpunkt der Anzeige zu erhalten
'''
#Überprüfen Sie, ob Sie eingeladen sind, und erhalten Sie eine Aufführung, an der Sie teilnehmen können
self.production = self.production_to_join()
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
'''Handler, um die Anfrage beim Speichern zu erhalten
'''
#Überprüfen Sie, ob Sie eingeladen sind, und erhalten Sie eine Aufführung, an der Sie teilnehmen können
self.production = self.production_to_join()
return super().post(request, *args, **kwargs)
product_to_join ()
zum Abrufen des Objekts der Leistung (Production
) des Teilnahmeziels lautet wie folgt.views.py
def production_to_join(self):
'''Überprüfen Sie, ob Sie eingeladen sind, und geben Sie eine Aufführung zurück, an der Sie teilnehmen können
'''
#Wirf einen 404-Fehler aus, wenn du nicht eingeladen wirst
invt_id = self.kwargs['invt_id'];
invts = Invitation.objects.filter(id=invt_id)
if len(invts) < 1:
raise Http404
invt = invts[0]
#Wirf einen 404-Fehler aus, wenn die Einladung abgelaufen ist
now = datetime.now(timezone.utc)
if now > invt.exp_dt:
raise Http404
#PermissionDenied, wenn der zugreifende Benutzer nicht eingeladen ist
user = self.request.user
if user != invt.invitee:
raise PermissionDenied
return invt.production
Bei ["Mechanismus zum Anzeigen empfangener Einladungen"](#Mechanismus zum Anzeigen empfangener Einladungen) ist der Parameter "invt_id" in den Link der Schaltfläche "Beitreten" eingebettet. Wir bekommen ein Staatsobjekt ("Einladung").
Der Pfad, um hierher zu gelangen (Ansicht, um an der Aufführung teilzunehmen), ist urls.py
wie folgt (> Quelle).
path('prod_join/<int:invt_id>/', views.ProdJoin.as_view(), name='prod_join'),
――Es ist besser, eine Nachricht über das Ablaufdatum anzuzeigen, aber hier wird einfach 404 zurückgegeben.
views.py
def form_valid(self, form):
'''Nach bestandener Validierung
'''
#Einladung prüfen
invt_id = self.kwargs['invt_id'];
invts = Invitation.objects.filter(id=invt_id)
if len(invts) < 1:
return self.form_invalid(form)
invt = invts[0]
#Holen Sie sich den Datensatz zum Speichern
new_prod_user = form.save(commit=False)
#Ist die richtige Leistung eingestellt?
if new_prod_user.production != invt.production:
return self.form_invalid(form)
#Ist der richtige Benutzer eingestellt?
if new_prod_user.user != invt.invitee:
return self.form_invalid(form)
#Einladung löschen
invt.delete()
messages.success(self.request, str(invt.production) + "Ich nahm teil an.")
return super().form_valid(form)
def form_invalid(self, form):
'''Wenn Sie nicht teilnehmen
'''
messages.warning(self.request, "Ich konnte nicht teilnehmen.")
return super().form_invalid(form)
Es ist eine einfache Seite mit nur einer Schaltfläche "Beitreten" und einer Schaltfläche "Später".
production_join.html
{% extends 'base.html' %}
{% block content %}
<h1 style="margin: 0px;">
<a href="{% url 'production:prod_list' %}">◀</a>
Nehmen Sie an der Aufführung teil
</h1>
<div> </div>
<p>
{{ view.production }}Wurden eingeladen zu. Sind Sie sicher, dass Sie teilnehmen möchten?
</p>
<form method="post">
{% csrf_token %}
<input type="hidden" name="production" value="{{ view.production.id }}">
<input type="hidden" name="user" value="{{ view.request.user.id }}">
<input type="submit" value="Beteiligung">
<input type="button"
onclick="location.href='{% url 'production:prod_list' %}'"
value="später">
</form>
{% endblock %}
Wir haben die Implementierung der Funktion eingeführt, um Benutzer zu einer "Projekteinheit" (Gruppe) namens "Leistung" einzuladen und den eingeladenen Benutzern die Teilnahme daran zu ermöglichen. Die verwendeten Techniken sind nachstehend zusammengefasst.
post ()
-Methode). ..hasattr ()
). Ich konnte validieren.kwargs
könnten später als self.kwargs
bezeichnet werden.Recommended Posts