Reputation: 2325
I have Django app using django-taggit
module. My work flow process is to add a photo, then come back to photo to assign tags using a photo_edit
view, photo_edit
form and photo_edit.html
template as shown below.
The app successfully tags the photo, using the 'tags': TagWidget()
in the form and template. This works fine, and it can save new, modified or deleted tags against that photo.
But I want to be able to record the user id of person adding tag in the django taggit
model database table. django taggit
doesn't have this feature.
To get started, I have successfully added a new user
field to the class TagBase(models.Model):
using settings.AUTH_USER_MODEL
to refer to user object which creates new user_id
column in the taggit_tags
table when makemigrations
is run.
Now I need to figure out how to get current user id to populate that new user_id
column when adding or editing tagged object tags.
I have tried doing this in both my app view and django taggit
model. Ideally, since this would be a default feature, the user id is saved in django taggit
model.
In django taggit
model I have tried adding self.user = get_user_model().objects.get(id=request.user.id)
to the TagBase
def save
function. But of course it doesn't know what request
is. I also tried creating new function in the TagBase
model class as below, and calling it from the def save
function but it returns nothing.
def get_user(request):
user = request.user
print('MODEL request user', request.user)
return user
As a test, I replaced request.user.id
with hard coded id eg self.user = get_user_model().objects.get(id=1)
which actually does write 1 to the taggit_tag
table user_id
field for that tag.
I tried doing this in the app view too. For example, I have tried photo.tag.user_id = request.user.id
before save_m2m()
which didn't work. It is not clear what syntax, if any, is available to save related model fields. I believe I would have to modify the form TagWidget()
to include user_id
field so save_2m2()
would save it, but want to avoid modifying django-taggit
too much.
I have searched exhaustively and have not found anything specific to Django and django-taggit
. Perhaps someone could help from Python perspective!
Photo edit form
class PhotoEditForm(ModelForm):
#filename = forms.ImageField()
class Meta:
model = Photo
fields = (
'tags',
)
widgets = {
'tags': TagWidget(),
}
Photo edit view - ideally i could save request.user
before form.save_m2m()
something like photo.taggit_tag.user_id = user.id
. Is there some syntax that would work here?
def photo_edit(request, photo_id):
photo = Photo.objects.get(id=int(photo_id))
user = get_user_model().objects.get(id=request.user.id)
photo_tags = Tag.objects.filter(photo=photo.id).order_by('name')
if request.method == "POST":
form = PhotoEditForm(request.POST, instance=photo)
if form.is_valid():
photo = form.save(commit=False)
photo.modified = timezone.now()
photo = form.save()
#save tags if any
form.save_m2m()
return HttpResponseRedirect(reverse('photo', kwargs={ 'photo_id': photo.id,}))
else:
form = PhotoEditForm(instance=photo)
context = {
'photo_form': form,
'photo': photo,
'photo_tags': photo_tags,
'title': 'Edit Mode',
}
return render(
request,
'photo_edit.html',
context,
)
Photo model
class Photo(models.Model):
filename = CloudinaryField('image')
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=True)
inactive = models.BooleanField(default=False, choices=INACTIVE_CHOICES)
created = models.DateTimeField(blank=True, null=True)
modified = models.DateTimeField(blank=True, null=True)
tags = TaggableManager()
class Meta:
managed = True
db_table = 'photo'
verbose_name_plural = 'photos'
def __str__(self):
return str(self.filename)
I did make slight modification of django taggit model to include user_id
field. Ideally i could set this user_id
to request.user
as default value but haven't seen anything yet that looks simple or easy.
class TagBase(models.Model):
name = models.CharField(verbose_name=_("Name"), unique=True, max_length=100)
slug = models.SlugField(verbose_name=_("Slug"), unique=True, max_length=100)
# added user to model which created `user_id` column on `taggit_tags` table
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=True)
def __str__(self):
return self.name
def __gt__(self, other):
return self.name.lower() > other.name.lower()
def __lt__(self, other):
return self.name.lower() < other.name.lower()
class Meta:
abstract = True
def save(self, *args, **kwargs):
self.user = get_user_model().objects.get(id=1)
if self._state.adding and not self.slug:
self.slug = self.slugify(self.name)
using = kwargs.get("using") or router.db_for_write(
type(self), instance=self
)
Upvotes: 0
Views: 538
Reputation: 446
You may want to look at django-crum: Django-CRUM (Current Request User Middleware) captures the current request and user in thread local storage.
I used it when tackling a similar issue. It allows you to access the current user without the request object having to be passed directly:
https://django-crum.readthedocs.io/en/stable/
Upvotes: 1